lightspeed-retail-sdk 3.1.2 → 3.2.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 +798 -268
- package/dist/index.cjs +1061 -143
- package/dist/index.mjs +1219 -138
- package/dist/src/bin/cli.js +1187 -0
- package/dist/src/core/LightspeedSDK.cjs +168 -31
- package/dist/src/core/LightspeedSDK.mjs +166 -32
- package/dist/src/storage/TokenStorage.cjs +248 -8
- package/dist/src/storage/TokenStorage.mjs +272 -13
- package/package.json +35 -20
- package/scripts/generate-key.js +13 -0
package/README.md
CHANGED
|
@@ -1,35 +1,431 @@
|
|
|
1
1
|
# Another Unofficial Lightspeed Retail V3 API SDK
|
|
2
2
|
|
|
3
|
-
A JavaScript SDK for interacting with the Lightspeed Retail API. This SDK provides a convenient way to access Lightspeed Retail's
|
|
3
|
+
A modern JavaScript SDK for interacting with the Lightspeed Retail API. This SDK provides a convenient, secure, and flexible way to access Lightspeed Retail's features—including customer, item, and order management.
|
|
4
4
|
|
|
5
|
-
**Current Version: 3.
|
|
5
|
+
**Current Version: 3.2.0** — Now with secure encrypted token storage using Node.js crypto. Useful CLI tools, database tools & email warnings on auth failure.
|
|
6
|
+
|
|
7
|
+
## **🆕 Recent Updates (v3.2.0)**
|
|
8
|
+
|
|
9
|
+
- **🎯 Enhanced Parameter Support**: All main getter methods now support both legacy and new object-based parameters with full backward compatibility
|
|
10
|
+
- **🔄 Flexible Method Signatures**: New object-based parameters support `{ relations, limit, timeStamp, sort }` for all collection methods
|
|
11
|
+
- **⚡ Improved Performance**: Smart pagination with single-page requests when `limit` is specified
|
|
12
|
+
- **🕒 Timestamp Filtering**: Filter records by modification time using ISO timestamp format
|
|
13
|
+
- **📊 Better Sorting**: Sort results by any field using the `sort` parameter
|
|
14
|
+
- **🔒 Enhanced Error Handling**: All GET methods now return consistent types, never `undefined`
|
|
15
|
+
- **🛠️ Robust API Error Recovery**: Graceful handling of bad requests and empty responses
|
|
16
|
+
- **🐛 Better Debugging**: Enhanced error logging with URLs, status codes, and response data
|
|
17
|
+
- **🔐 Type Safety**: Guaranteed array returns for all list methods
|
|
18
|
+
- **📈 Method Coverage**: Updated 20+ methods with new parameter support including getItems, getCustomers, getSales, getOrders, and more
|
|
19
|
+
|
|
20
|
+
## 🚀 Key Features
|
|
21
|
+
|
|
22
|
+
- **Modern API**: Object-based parameters with full backward compatibility
|
|
23
|
+
- **Timestamp Filtering**: Get only records updated since a specific time
|
|
24
|
+
- **Robust Error Handling**: Clean, silent error handling with consistent return types
|
|
25
|
+
- **Enhanced CLI**: Browser selection, default scopes, and improved authentication
|
|
26
|
+
- **Multiple Storage Options**: File, encrypted, database, and in-memory token storage
|
|
27
|
+
- **Comprehensive Coverage**: 20+ API methods with consistent interfaces
|
|
28
|
+
|
|
29
|
+
## 🔄 Migrating from 3.1.x
|
|
30
|
+
|
|
31
|
+
### Backward Compatibility
|
|
32
|
+
|
|
33
|
+
All existing code continues to work unchanged. **No breaking changes in 3.2.0**.
|
|
34
|
+
|
|
35
|
+
### New Features Available
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// Old way (still works)
|
|
39
|
+
const items = await sdk.getItems("Category,Vendor", 50);
|
|
40
|
+
|
|
41
|
+
// New way (recommended)
|
|
42
|
+
const items = await sdk.getItems({
|
|
43
|
+
relations: "Category,Vendor",
|
|
44
|
+
limit: 50,
|
|
45
|
+
timeStamp: "2025-01-01T00:00:00.000Z"
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Enhanced Error Handling
|
|
50
|
+
|
|
51
|
+
- Methods now return empty arrays instead of undefined on errors
|
|
52
|
+
- Less verbose logging for common API failures
|
|
53
|
+
- Consistent error handling across all methods
|
|
54
|
+
|
|
55
|
+
### What's New in 3.2.0
|
|
56
|
+
|
|
57
|
+
- **Object-based parameters** for all 20+ collection methods
|
|
58
|
+
- **Timestamp filtering** to get only recent changes
|
|
59
|
+
- **Clean error handling** with minimal logging
|
|
60
|
+
- **Enhanced CLI** with browser selection and better defaults
|
|
61
|
+
- **Improved token management** with better error recovery
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Table of Contents
|
|
66
|
+
|
|
67
|
+
- [Another Unofficial Lightspeed Retail V3 API SDK](#another-unofficial-lightspeed-retail-v3-api-sdk)
|
|
68
|
+
- [**🆕 Recent Updates (v3.2.0)**](#-recent-updates-v320)
|
|
69
|
+
- [🚀 Key Features](#-key-features)
|
|
70
|
+
- [🔄 Migrating from 3.1.x](#-migrating-from-31x)
|
|
71
|
+
- [Table of Contents](#table-of-contents)
|
|
72
|
+
- [🚨 Important Update - New OAuth System](#-important-update---new-oauth-system)
|
|
73
|
+
- [Key Changes](#key-changes)
|
|
74
|
+
- [Interactive CLI](#interactive-cli)
|
|
75
|
+
- [Getting Started with the CLI](#getting-started-with-the-cli)
|
|
76
|
+
- [Available CLI Commands](#available-cli-commands)
|
|
77
|
+
- [Authentication \& Setup](#authentication--setup)
|
|
78
|
+
- [Storage Management](#storage-management)
|
|
79
|
+
- [Email Testing](#email-testing)
|
|
80
|
+
- [CLI Features](#cli-features)
|
|
81
|
+
- [Interactive Storage Selection](#interactive-storage-selection)
|
|
82
|
+
- [OAuth Authentication Flow](#oauth-authentication-flow)
|
|
83
|
+
- [Token Management](#token-management)
|
|
84
|
+
- [Manual Token Refresh](#manual-token-refresh)
|
|
85
|
+
- [Token Status Checking](#token-status-checking)
|
|
86
|
+
- [Database Setup Wizard](#database-setup-wizard)
|
|
87
|
+
- [Token Migration](#token-migration)
|
|
88
|
+
- [Security Features](#security-features)
|
|
89
|
+
- [Email Notifications](#email-notifications)
|
|
90
|
+
- [CLI Configuration](#cli-configuration)
|
|
91
|
+
- [CLI Examples](#cli-examples)
|
|
92
|
+
- [Features](#features)
|
|
93
|
+
- [Smart Token Management](#smart-token-management)
|
|
94
|
+
- [Token Priority Order](#token-priority-order)
|
|
95
|
+
- [Environment Variables](#environment-variables)
|
|
96
|
+
- [Installation](#installation)
|
|
97
|
+
- [Global CLI Installation (Recommended)](#global-cli-installation-recommended)
|
|
98
|
+
- [Local Installation](#local-installation)
|
|
99
|
+
- [Configuration](#configuration)
|
|
100
|
+
- [Quick Start](#quick-start)
|
|
101
|
+
- [Modern CLI-First Approach (Recommended)](#modern-cli-first-approach-recommended)
|
|
102
|
+
- [Alternative: Local Installation](#alternative-local-installation)
|
|
103
|
+
- [Basic Usage (In-Memory Storage)](#basic-usage-in-memory-storage)
|
|
104
|
+
- [Manual Token Management (Advanced)](#manual-token-management-advanced)
|
|
105
|
+
- [File-Based Storage](#file-based-storage)
|
|
106
|
+
- [Encrypted Storage (Recommended)](#encrypted-storage-recommended)
|
|
107
|
+
- [Database Storage (PostgreSQL, SQLite, and MongoDB)](#database-storage-postgresql-sqlite-and-mongodb)
|
|
108
|
+
- [Database Setup](#database-setup)
|
|
109
|
+
- [Option 1: Use the CLI (Recommended)](#option-1-use-the-cli-recommended)
|
|
110
|
+
- [Option 2: Manual Setup](#option-2-manual-setup)
|
|
111
|
+
- [PostgreSQL Schema](#postgresql-schema)
|
|
112
|
+
- [SQLite Schema](#sqlite-schema)
|
|
113
|
+
- [MongoDB Schema](#mongodb-schema)
|
|
114
|
+
- [Example: Using DatabaseTokenStorage](#example-using-databasetokenstorage)
|
|
115
|
+
- [Notes](#notes)
|
|
116
|
+
- [Custom Storage Interface (Advanced)](#custom-storage-interface-advanced)
|
|
117
|
+
- [CommonJS Usage](#commonjs-usage)
|
|
118
|
+
- [ES Modules (Recommended)](#es-modules-recommended)
|
|
119
|
+
- [CommonJS](#commonjs)
|
|
120
|
+
- [Migration from Previous Versions](#migration-from-previous-versions)
|
|
121
|
+
- [API Methods](#api-methods)
|
|
122
|
+
- [Enhanced Parameter Support](#enhanced-parameter-support)
|
|
123
|
+
- [Legacy Parameter Syntax (Still Supported)](#legacy-parameter-syntax-still-supported)
|
|
124
|
+
- [New Object-Based Parameter Syntax](#new-object-based-parameter-syntax)
|
|
125
|
+
- [Available Parameters](#available-parameters)
|
|
126
|
+
- [Core Resources](#core-resources)
|
|
127
|
+
- [Customers](#customers)
|
|
128
|
+
- [Items](#items)
|
|
129
|
+
- [Matrix Items](#matrix-items)
|
|
130
|
+
- [Categories](#categories)
|
|
131
|
+
- [Manufacturers](#manufacturers)
|
|
132
|
+
- [Vendors](#vendors)
|
|
133
|
+
- [Orders](#orders)
|
|
134
|
+
- [Sales](#sales)
|
|
135
|
+
- [Sale Lines](#sale-lines)
|
|
136
|
+
- [Account \& Configuration](#account--configuration)
|
|
137
|
+
- [Account Information](#account-information)
|
|
138
|
+
- [Employees](#employees)
|
|
139
|
+
- [System Configuration](#system-configuration)
|
|
140
|
+
- [Gift Cards \& Special Orders](#gift-cards--special-orders)
|
|
141
|
+
- [Images](#images)
|
|
142
|
+
- [Utility Methods](#utility-methods)
|
|
143
|
+
- [Error Handling](#error-handling)
|
|
144
|
+
- [**Automatic Error Recovery**](#automatic-error-recovery)
|
|
145
|
+
- [**Safe Return Types**](#safe-return-types)
|
|
146
|
+
- [**Enhanced Error Logging**](#enhanced-error-logging)
|
|
147
|
+
- [**Graceful Degradation**](#graceful-degradation)
|
|
148
|
+
- [Rate Limiting](#rate-limiting)
|
|
149
|
+
- [Pagination](#pagination)
|
|
150
|
+
- [Contributing](#contributing)
|
|
151
|
+
- [License](#license)
|
|
152
|
+
- [Disclaimer](#disclaimer)
|
|
153
|
+
- [More Info](#more-info)
|
|
6
154
|
|
|
7
155
|
## 🚨 Important Update - New OAuth System
|
|
8
156
|
|
|
9
|
-
**Lightspeed has implemented a new OAuth authorization server.** This SDK
|
|
157
|
+
**Lightspeed has implemented a new OAuth authorization server.** This SDK is fully updated to support the new endpoints and token rotation system.
|
|
10
158
|
|
|
11
159
|
### Key Changes
|
|
12
160
|
|
|
13
|
-
- **NEW: Encrypted token storage**
|
|
14
|
-
- **New OAuth endpoints**
|
|
15
|
-
- **Token rotation**
|
|
16
|
-
- **Token persistence**
|
|
17
|
-
- **Longer token values**
|
|
161
|
+
- **NEW: Encrypted token storage** — Secure your tokens at rest with built-in AES-256-GCM encryption using Node.js crypto
|
|
162
|
+
- **New OAuth endpoints** — Uses `https://cloud.lightspeedapp.com/auth/oauth/token`
|
|
163
|
+
- **Token rotation** — Both access and refresh tokens now change with each refresh
|
|
164
|
+
- **Token persistence** — Tokens must be stored between application restarts
|
|
165
|
+
- **Longer token values** — Ensure your storage can handle the new token lengths
|
|
166
|
+
|
|
167
|
+
## Interactive CLI
|
|
168
|
+
|
|
169
|
+
The SDK includes a powerful interactive CLI for easy setup, authentication, and token management. No coding required!
|
|
170
|
+
|
|
171
|
+
### Getting Started with the CLI
|
|
172
|
+
|
|
173
|
+
The CLI provides an interactive way to:
|
|
174
|
+
|
|
175
|
+
- Authenticate with Lightspeed OAuth
|
|
176
|
+
- Manage tokens across different storage backends
|
|
177
|
+
- Set up database storage
|
|
178
|
+
- Migrate tokens between storage systems
|
|
179
|
+
- View account information
|
|
180
|
+
|
|
181
|
+
### Available CLI Commands
|
|
182
|
+
|
|
183
|
+
> **Note**: The examples below assume global installation (`npm install -g lightspeed-retail-sdk`). If you installed locally, prefix commands with `npx` (e.g., `npx lightspeed-retail-sdk login`).
|
|
184
|
+
|
|
185
|
+
#### Authentication & Setup
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Start OAuth authentication flow
|
|
189
|
+
lightspeed-retail-sdk login
|
|
190
|
+
|
|
191
|
+
# Start OAuth authentication with specific browser
|
|
192
|
+
lightspeed-retail-sdk login --browser firefox
|
|
193
|
+
lightspeed-retail-sdk login --browser "google chrome"
|
|
194
|
+
lightspeed-retail-sdk login --browser safari
|
|
195
|
+
|
|
196
|
+
# Check current token status
|
|
197
|
+
lightspeed-retail-sdk token-status
|
|
198
|
+
|
|
199
|
+
# Manually refresh stored access token
|
|
200
|
+
lightspeed-retail-sdk refresh-token
|
|
201
|
+
|
|
202
|
+
# View your account information
|
|
203
|
+
lightspeed-retail-sdk whoami
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Storage Management
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Set up database storage (SQLite, Postgres, MongoDB)
|
|
210
|
+
lightspeed-retail-sdk setup-db
|
|
211
|
+
|
|
212
|
+
# Clear stored tokens
|
|
213
|
+
lightspeed-retail-sdk reset
|
|
214
|
+
|
|
215
|
+
# Migrate tokens between storage backends
|
|
216
|
+
lightspeed-retail-sdk migrate-tokens
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### Email Testing
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Test email notification system
|
|
223
|
+
lightspeed-retail-sdk test-email
|
|
224
|
+
|
|
225
|
+
# Test with custom account ID
|
|
226
|
+
lightspeed-retail-sdk test-email --account-id "YOUR-ACCOUNT-ID"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### CLI Features
|
|
230
|
+
|
|
231
|
+
#### Interactive Storage Selection
|
|
232
|
+
|
|
233
|
+
The CLI automatically prompts you to choose your preferred storage backend:
|
|
234
|
+
|
|
235
|
+
- **File Storage** - Simple JSON file storage
|
|
236
|
+
- **Encrypted File Storage** - AES-256-GCM encrypted file storage (recommended)
|
|
237
|
+
- **Encrypted Database Storage** - SQLite, PostgreSQL, or MongoDB (always encrypted)
|
|
238
|
+
|
|
239
|
+
#### OAuth Authentication Flow
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
lightspeed-retail-sdk login
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The login process:
|
|
246
|
+
|
|
247
|
+
1. Prompts for your Lightspeed credentials (if not in environment)
|
|
248
|
+
2. Optionally lets you choose a specific browser
|
|
249
|
+
3. Opens browser for OAuth authorization
|
|
250
|
+
4. Automatically exchanges code for tokens
|
|
251
|
+
5. Stores tokens in your chosen backend
|
|
252
|
+
|
|
253
|
+
**Note**: If no scopes are specified via environment variables or user input, the default scope `employee:all` will be used.
|
|
254
|
+
|
|
255
|
+
**Browser Options:**
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Use default browser
|
|
259
|
+
lightspeed-retail-sdk login
|
|
260
|
+
|
|
261
|
+
# Specify browser via command line
|
|
262
|
+
lightspeed-retail-sdk login --browser firefox
|
|
263
|
+
lightspeed-retail-sdk login --browser "google chrome"
|
|
264
|
+
|
|
265
|
+
# Interactive browser selection (when no --browser flag is used)
|
|
266
|
+
# The CLI will ask if you want to choose a specific browser
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Token Management
|
|
270
|
+
|
|
271
|
+
##### Manual Token Refresh
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
lightspeed-retail-sdk refresh-token
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Use this command to:
|
|
278
|
+
|
|
279
|
+
- Test your refresh token before it expires
|
|
280
|
+
- Force a token refresh for testing purposes
|
|
281
|
+
- Update access tokens without full re-authentication
|
|
282
|
+
- Verify that your stored credentials are working
|
|
283
|
+
|
|
284
|
+
The command will:
|
|
285
|
+
|
|
286
|
+
- Show current token expiration status
|
|
287
|
+
- Attempt to refresh using stored refresh token
|
|
288
|
+
- Display the new token information
|
|
289
|
+
- Handle token rotation if enabled by Lightspeed
|
|
290
|
+
|
|
291
|
+
##### Token Status Checking
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
lightspeed-retail-sdk token-status
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Shows detailed information about your stored tokens including expiration times.
|
|
298
|
+
|
|
299
|
+
#### Database Setup Wizard
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
lightspeed-retail-sdk setup-db
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
- Guides you through database connection setup
|
|
306
|
+
- Creates required tables/collections
|
|
307
|
+
- Tests database connectivity
|
|
308
|
+
- Supports local and cloud databases
|
|
309
|
+
|
|
310
|
+
#### Token Migration
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
lightspeed-retail-sdk migrate-tokens
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
- Move tokens between any supported storage backends
|
|
317
|
+
- Automatically creates destination storage if needed
|
|
318
|
+
- Confirms before overwriting existing tokens
|
|
319
|
+
- Validates successful migration
|
|
320
|
+
|
|
321
|
+
#### Security Features
|
|
322
|
+
|
|
323
|
+
- **Database tokens are always encrypted** - Uses AES-256-GCM encryption automatically
|
|
324
|
+
- **Secure credential prompting** - Sensitive inputs are handled securely
|
|
325
|
+
- **Environment variable support** - Use `.env` files for configuration
|
|
326
|
+
- **Connection cleanup** - Proper database connection management
|
|
327
|
+
|
|
328
|
+
#### Email Notifications
|
|
329
|
+
|
|
330
|
+
The SDK can automatically send email alerts when token refresh fails:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Configure SMTP settings in your .env file
|
|
334
|
+
SMTP_HOST=smtp.gmail.com
|
|
335
|
+
SMTP_PORT=587
|
|
336
|
+
SMTP_SECURE=false # true for 465, false for other ports
|
|
337
|
+
SMTP_USER=your-email@gmail.com
|
|
338
|
+
SMTP_PASS=your-app-password # Use app passwords for Gmail
|
|
339
|
+
SMTP_FROM=your-email@gmail.com # Optional, defaults to SMTP_USER
|
|
340
|
+
ALERT_EMAIL=admin@yourcompany.com
|
|
341
|
+
|
|
342
|
+
# Test the email system
|
|
343
|
+
lightspeed-retail-sdk test-email
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Email Features:**
|
|
347
|
+
|
|
348
|
+
- Automatic alerts on token refresh failures
|
|
349
|
+
- Detailed error information and recovery steps
|
|
350
|
+
- Configurable SMTP settings
|
|
351
|
+
- Built-in test command for validation
|
|
352
|
+
|
|
353
|
+
### CLI Configuration
|
|
354
|
+
|
|
355
|
+
You can configure the CLI using environment variables:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
# Token storage location
|
|
359
|
+
LIGHTSPEED_TOKEN_FILE=./tokens/encrypted-tokens.json
|
|
360
|
+
|
|
361
|
+
# Encryption key for secure storage
|
|
362
|
+
LIGHTSPEED_ENCRYPTION_KEY=your_64_char_hex_key
|
|
363
|
+
|
|
364
|
+
# Database connections (for database storage)
|
|
365
|
+
LIGHTSPEED_POSTGRES_URL=postgres://user:pass@host:5432/db
|
|
366
|
+
LIGHTSPEED_MONGO_URL=mongodb://localhost:27017/lightspeed
|
|
367
|
+
|
|
368
|
+
# OAuth credentials
|
|
369
|
+
LIGHTSPEED_CLIENT_ID=your_client_id
|
|
370
|
+
LIGHTSPEED_CLIENT_SECRET=your_client_secret
|
|
371
|
+
LIGHTSPEED_ACCOUNT_ID=your_account_id
|
|
372
|
+
LIGHTSPEED_REDIRECT_URL=your_lightspeed_redirect_url
|
|
373
|
+
|
|
374
|
+
# Optional: OAuth scopes (defaults to "employee:all" if not specified)
|
|
375
|
+
LIGHTSPEED_SCOPES=employee:all inventory:all
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### CLI Examples
|
|
379
|
+
|
|
380
|
+
**Complete setup from scratch:**
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
# 1. Generate encryption key and add to .env
|
|
384
|
+
node -e "console.log('LIGHTSPEED_ENCRYPTION_KEY=' + require('crypto').randomBytes(32).toString('hex'))"
|
|
385
|
+
|
|
386
|
+
# 2. Set up database storage
|
|
387
|
+
lightspeed-retail-sdk setup-db
|
|
388
|
+
|
|
389
|
+
# 3. Authenticate and store tokens (with browser choice)
|
|
390
|
+
lightspeed-retail-sdk login --browser firefox
|
|
391
|
+
|
|
392
|
+
# 4. Verify setup
|
|
393
|
+
lightspeed-retail-sdk whoami
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Migrate from file to database:**
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
lightspeed-retail-sdk migrate-tokens
|
|
400
|
+
# Select "Encrypted File" as source
|
|
401
|
+
# Select "Encrypted Database" as destination
|
|
402
|
+
# Choose your database type and connection
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**Check token status:**
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
lightspeed-retail-sdk token-status
|
|
409
|
+
# Shows token validity, expiration, and storage location
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
The CLI makes it easy to get started with the SDK without writing any configuration code!
|
|
18
413
|
|
|
19
414
|
## Features
|
|
20
415
|
|
|
21
|
-
- **
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- **
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
416
|
+
- **Interactive CLI** — Complete command-line interface for authentication, token management, and database setup
|
|
417
|
+
- **Encrypted token storage** — Secure your tokens at rest with built-in AES-256-GCM encryption using Node.js crypto
|
|
418
|
+
- **Email notifications** — Automatic alerts for token refresh failures with configurable SMTP settings
|
|
419
|
+
- **Flexible storage backends** — File-based, encrypted, database (SQLite, PostgreSQL, MongoDB), or custom storage options
|
|
420
|
+
- **Smart token management** — Automatic refresh, rotation handling, and persistent storage
|
|
421
|
+
- **Auto-retry on authentication errors** — Automatically refreshes tokens and retries failed requests
|
|
422
|
+
- Easy-to-use methods for all major Lightspeed Retail endpoints
|
|
423
|
+
- Built-in handling of API rate limits and pagination
|
|
424
|
+
- Retry logic for transient network issues
|
|
425
|
+
- Advanced search capabilities for items and customers
|
|
426
|
+
- Bulk operations for efficient data updates
|
|
427
|
+
- Inventory management with low stock alerts and category queries
|
|
428
|
+
- Support for both CommonJS and ES modules
|
|
33
429
|
|
|
34
430
|
## Smart Token Management
|
|
35
431
|
|
|
@@ -60,6 +456,19 @@ LIGHTSPEED_CLIENT_SECRET=your_client_secret
|
|
|
60
456
|
LIGHTSPEED_ACCESS_TOKEN=your_access_token
|
|
61
457
|
LIGHTSPEED_REFRESH_TOKEN=your_refresh_token
|
|
62
458
|
LIGHTSPEED_TOKEN_EXPIRES_AT=2025-01-01T00:00:00.000Z
|
|
459
|
+
|
|
460
|
+
# Storage Configuration (CLI only)
|
|
461
|
+
LIGHTSPEED_TOKEN_FILE=./tokens/encrypted-tokens.json
|
|
462
|
+
LIGHTSPEED_ENCRYPTION_KEY=your-64-character-encryption-key
|
|
463
|
+
|
|
464
|
+
# Email Notifications (Optional)
|
|
465
|
+
SMTP_HOST=smtp.gmail.com
|
|
466
|
+
SMTP_PORT=587
|
|
467
|
+
SMTP_SECURE=false
|
|
468
|
+
SMTP_USER=your-email@gmail.com
|
|
469
|
+
SMTP_PASS=your-app-password
|
|
470
|
+
SMTP_FROM=your-email@gmail.com
|
|
471
|
+
ALERT_EMAIL=admin@yourcompany.com
|
|
63
472
|
```
|
|
64
473
|
|
|
65
474
|
⚠️ **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.
|
|
@@ -70,8 +479,160 @@ LIGHTSPEED_TOKEN_EXPIRES_AT=2025-01-01T00:00:00.000Z
|
|
|
70
479
|
npm install lightspeed-retail-sdk
|
|
71
480
|
```
|
|
72
481
|
|
|
482
|
+
### Global CLI Installation (Recommended)
|
|
483
|
+
|
|
484
|
+
For the best experience, install the SDK globally to access the CLI from anywhere:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
npm install -g lightspeed-retail-sdk
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Once installed globally, you can use the CLI directly:
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
lightspeed-retail-sdk help
|
|
494
|
+
lightspeed-retail-sdk login
|
|
495
|
+
lightspeed-retail-sdk token-status
|
|
496
|
+
lightspeed-retail-sdk whoami
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Local Installation
|
|
500
|
+
|
|
501
|
+
If you prefer local installation or are using the SDK in a specific project:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
npm install lightspeed-retail-sdk
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Then use the CLI with `npx`:
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
npx lightspeed-retail-sdk help
|
|
511
|
+
npx lightspeed-retail-sdk login
|
|
512
|
+
npx lightspeed-retail-sdk token-status
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Or add scripts to your `package.json`:
|
|
516
|
+
|
|
517
|
+
```json
|
|
518
|
+
{
|
|
519
|
+
"scripts": {
|
|
520
|
+
"lightspeed-setup": "lightspeed-retail-sdk login",
|
|
521
|
+
"lightspeed-status": "lightspeed-retail-sdk token-status",
|
|
522
|
+
"lightspeed-refresh": "lightspeed-retail-sdk refresh-token"
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Then run:
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
npm run lightspeed-setup
|
|
531
|
+
npm run lightspeed-status
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Configuration
|
|
535
|
+
|
|
536
|
+
Create a `.env` file in your project root (where you'll run the CLI commands) with your Lightspeed credentials:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
# Required OAuth credentials
|
|
540
|
+
LIGHTSPEED_CLIENT_ID=your_client_id
|
|
541
|
+
LIGHTSPEED_CLIENT_SECRET=your_client_secret
|
|
542
|
+
LIGHTSPEED_ACCOUNT_ID=your_account_id
|
|
543
|
+
LIGHTSPEED_REDIRECT_URL=your_redirect_url
|
|
544
|
+
|
|
545
|
+
# Optional: Storage configuration
|
|
546
|
+
LIGHTSPEED_TOKEN_FILE=./tokens/encrypted-tokens.json
|
|
547
|
+
LIGHTSPEED_ENCRYPTION_KEY=your_64_char_hex_key
|
|
548
|
+
|
|
549
|
+
# Optional: Database connections
|
|
550
|
+
LIGHTSPEED_POSTGRES_URL=postgres://user:pass@host:5432/db
|
|
551
|
+
LIGHTSPEED_MONGO_URL=mongodb://localhost:27017/lightspeed
|
|
552
|
+
|
|
553
|
+
# Optional: Email notifications
|
|
554
|
+
SMTP_HOST=smtp.gmail.com
|
|
555
|
+
SMTP_PORT=587
|
|
556
|
+
SMTP_SECURE=false
|
|
557
|
+
SMTP_USER=your-email@gmail.com
|
|
558
|
+
SMTP_PASS=your-app-password
|
|
559
|
+
ALERT_EMAIL=admin@yourcompany.com
|
|
560
|
+
|
|
561
|
+
# Optional: OAuth scopes (defaults to "employee:all")
|
|
562
|
+
LIGHTSPEED_SCOPES=employee:all
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Generate an encryption key for secure token storage:
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Run this command to generate a secure encryption key
|
|
569
|
+
node -e "console.log('LIGHTSPEED_ENCRYPTION_KEY=' + require('crypto').randomBytes(32).toString('hex'))"
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Add the generated key to your `.env` file.
|
|
573
|
+
|
|
574
|
+
> **Note**: The CLI will read configuration from the `.env` file in your current working directory, making setup much easier by reducing the number of prompts.
|
|
575
|
+
|
|
73
576
|
## Quick Start
|
|
74
577
|
|
|
578
|
+
### Modern CLI-First Approach (Recommended)
|
|
579
|
+
|
|
580
|
+
The easiest way to get started is using the interactive CLI to handle authentication:
|
|
581
|
+
|
|
582
|
+
```bash
|
|
583
|
+
# 1. Install the SDK globally
|
|
584
|
+
npm install -g lightspeed-retail-sdk
|
|
585
|
+
|
|
586
|
+
# 2. Authenticate using CLI (one-time setup)
|
|
587
|
+
lightspeed-retail-sdk login
|
|
588
|
+
|
|
589
|
+
# 3. Use the SDK in your code
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
#### Alternative: Local Installation
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
# 1. Install the SDK locally
|
|
596
|
+
npm install lightspeed-retail-sdk
|
|
597
|
+
|
|
598
|
+
# 2. Authenticate using CLI (one-time setup)
|
|
599
|
+
npx lightspeed-retail-sdk login
|
|
600
|
+
|
|
601
|
+
# 3. Use the SDK in your code
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Then in your code:
|
|
605
|
+
|
|
606
|
+
```javascript
|
|
607
|
+
import LightspeedRetailSDK, {
|
|
608
|
+
FileTokenStorage,
|
|
609
|
+
EncryptedTokenStorage,
|
|
610
|
+
} from "lightspeed-retail-sdk";
|
|
611
|
+
import dotenv from "dotenv";
|
|
612
|
+
dotenv.config();
|
|
613
|
+
|
|
614
|
+
// Use the same storage configuration as your CLI
|
|
615
|
+
const fileStorage = new FileTokenStorage(
|
|
616
|
+
process.env.LIGHTSPEED_TOKEN_FILE || "./tokens/encrypted-tokens.json"
|
|
617
|
+
);
|
|
618
|
+
const tokenStorage = process.env.LIGHTSPEED_ENCRYPTION_KEY
|
|
619
|
+
? new EncryptedTokenStorage(
|
|
620
|
+
fileStorage,
|
|
621
|
+
process.env.LIGHTSPEED_ENCRYPTION_KEY
|
|
622
|
+
)
|
|
623
|
+
: fileStorage;
|
|
624
|
+
|
|
625
|
+
const api = new LightspeedRetailSDK({
|
|
626
|
+
accountID: process.env.LIGHTSPEED_ACCOUNT_ID,
|
|
627
|
+
clientID: process.env.LIGHTSPEED_CLIENT_ID,
|
|
628
|
+
clientSecret: process.env.LIGHTSPEED_CLIENT_SECRET,
|
|
629
|
+
tokenStorage,
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// The SDK will automatically use stored tokens and refresh as needed
|
|
633
|
+
export default api;
|
|
634
|
+
```
|
|
635
|
+
|
|
75
636
|
### Basic Usage (In-Memory Storage)
|
|
76
637
|
|
|
77
638
|
```javascript
|
|
@@ -88,7 +649,9 @@ const api = new LightspeedRetailSDK({
|
|
|
88
649
|
|
|
89
650
|
⚠️ **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.
|
|
90
651
|
|
|
91
|
-
###
|
|
652
|
+
### Manual Token Management (Advanced)
|
|
653
|
+
|
|
654
|
+
If you prefer to handle authentication manually without the CLI:
|
|
92
655
|
|
|
93
656
|
#### File-Based Storage
|
|
94
657
|
|
|
@@ -113,7 +676,7 @@ You can now store your tokens **encrypted at rest** using the built-in `Encrypte
|
|
|
113
676
|
**Generate a key** (if you haven't already):
|
|
114
677
|
|
|
115
678
|
```bash
|
|
116
|
-
|
|
679
|
+
node -e "console.log('LIGHTSPEED_ENCRYPTION_KEY=' + require('crypto').randomBytes(32).toString('hex'))"
|
|
117
680
|
```
|
|
118
681
|
|
|
119
682
|
Add the generated key to your `.env` file:
|
|
@@ -125,8 +688,10 @@ LIGHTSPEED_ENCRYPTION_KEY=your_64_char_hex_key_here
|
|
|
125
688
|
**Usage Example:**
|
|
126
689
|
|
|
127
690
|
```javascript
|
|
128
|
-
import LightspeedRetailSDK, {
|
|
129
|
-
|
|
691
|
+
import LightspeedRetailSDK, {
|
|
692
|
+
FileTokenStorage,
|
|
693
|
+
EncryptedTokenStorage,
|
|
694
|
+
} from "lightspeed-retail-sdk";
|
|
130
695
|
import dotenv from "dotenv";
|
|
131
696
|
dotenv.config();
|
|
132
697
|
|
|
@@ -157,225 +722,123 @@ Keep your encryption key secure and never commit it to version control!
|
|
|
157
722
|
|
|
158
723
|
---
|
|
159
724
|
|
|
160
|
-
|
|
725
|
+
## Database Storage (PostgreSQL, SQLite, and MongoDB)
|
|
161
726
|
|
|
162
|
-
|
|
727
|
+
### Database Setup
|
|
163
728
|
|
|
164
|
-
|
|
165
|
-
import LightspeedRetailSDK, {
|
|
166
|
-
DatabaseTokenStorage,
|
|
167
|
-
} from "lightspeed-retail-sdk";
|
|
168
|
-
import mysql from "mysql2/promise";
|
|
729
|
+
#### Option 1: Use the CLI (Recommended)
|
|
169
730
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
this.config = connectionConfig;
|
|
174
|
-
this.userId = userId;
|
|
175
|
-
}
|
|
731
|
+
```bash
|
|
732
|
+
lightspeed-retail-sdk setup-db
|
|
733
|
+
```
|
|
176
734
|
|
|
177
|
-
|
|
178
|
-
const connection = await mysql.createConnection(this.config);
|
|
179
|
-
try {
|
|
180
|
-
const [rows] = await connection.execute(
|
|
181
|
-
"SELECT access_token, refresh_token, expires_at FROM user_tokens WHERE user_id = ?",
|
|
182
|
-
[this.userId]
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
if (rows.length === 0) {
|
|
186
|
-
return { access_token: null, refresh_token: null, expires_at: null };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
access_token: rows[0].access_token,
|
|
191
|
-
refresh_token: rows[0].refresh_token,
|
|
192
|
-
expires_at: rows[0].expires_at,
|
|
193
|
-
};
|
|
194
|
-
} finally {
|
|
195
|
-
await connection.end();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
735
|
+
The CLI will guide you through creating the required tables/collections for your database.
|
|
198
736
|
|
|
199
|
-
|
|
200
|
-
const connection = await mysql.createConnection(this.config);
|
|
201
|
-
try {
|
|
202
|
-
await connection.execute(
|
|
203
|
-
`INSERT INTO user_tokens (user_id, access_token, refresh_token, expires_at, updated_at)
|
|
204
|
-
VALUES (?, ?, ?, ?, NOW())
|
|
205
|
-
ON DUPLICATE KEY UPDATE
|
|
206
|
-
access_token = VALUES(access_token),
|
|
207
|
-
refresh_token = VALUES(refresh_token),
|
|
208
|
-
expires_at = VALUES(expires_at),
|
|
209
|
-
updated_at = NOW()`,
|
|
210
|
-
[
|
|
211
|
-
this.userId,
|
|
212
|
-
tokens.access_token,
|
|
213
|
-
tokens.refresh_token,
|
|
214
|
-
tokens.expires_at,
|
|
215
|
-
]
|
|
216
|
-
);
|
|
217
|
-
} finally {
|
|
218
|
-
await connection.end();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
737
|
+
#### Option 2: Manual Setup
|
|
222
738
|
|
|
223
|
-
|
|
224
|
-
const dbConfig = {
|
|
225
|
-
host: "localhost",
|
|
226
|
-
user: "your_user",
|
|
227
|
-
password: "your_password",
|
|
228
|
-
database: "your_database",
|
|
229
|
-
};
|
|
739
|
+
If you prefer to create the database schema manually, use the schemas below:
|
|
230
740
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
741
|
+
### PostgreSQL Schema
|
|
742
|
+
|
|
743
|
+
```sql
|
|
744
|
+
CREATE TABLE oauth_tokens (
|
|
745
|
+
app_id TEXT PRIMARY KEY,
|
|
746
|
+
tokens JSONB NOT NULL
|
|
747
|
+
);
|
|
238
748
|
```
|
|
239
749
|
|
|
240
|
-
|
|
750
|
+
- `app_id`: Used to support multiple apps or tenants (default is `"default"`).
|
|
751
|
+
- `tokens`: Stores the full token object as JSON.
|
|
241
752
|
|
|
242
|
-
|
|
243
|
-
import { DatabaseTokenStorage } from "lightspeed-retail-sdk";
|
|
244
|
-
import pg from "pg";
|
|
753
|
+
### SQLite Schema
|
|
245
754
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
755
|
+
```sql
|
|
756
|
+
CREATE TABLE oauth_tokens (
|
|
757
|
+
app_id TEXT PRIMARY KEY,
|
|
758
|
+
tokens TEXT NOT NULL
|
|
759
|
+
);
|
|
760
|
+
```
|
|
252
761
|
|
|
253
|
-
|
|
254
|
-
const client = new pg.Client(this.connectionString);
|
|
255
|
-
await client.connect();
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
const result = await client.query(
|
|
259
|
-
"SELECT access_token, refresh_token, expires_at FROM user_tokens WHERE user_id = $1",
|
|
260
|
-
[this.userId]
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
if (result.rows.length === 0) {
|
|
264
|
-
return { access_token: null, refresh_token: null, expires_at: null };
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const row = result.rows[0];
|
|
268
|
-
return {
|
|
269
|
-
access_token: row.access_token,
|
|
270
|
-
refresh_token: row.refresh_token,
|
|
271
|
-
expires_at: row.expires_at,
|
|
272
|
-
};
|
|
273
|
-
} finally {
|
|
274
|
-
await client.end();
|
|
275
|
-
}
|
|
276
|
-
}
|
|
762
|
+
- `tokens` is stored as a JSON string.
|
|
277
763
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
updated_at = NOW()`,
|
|
291
|
-
[
|
|
292
|
-
this.userId,
|
|
293
|
-
tokens.access_token,
|
|
294
|
-
tokens.refresh_token,
|
|
295
|
-
tokens.expires_at,
|
|
296
|
-
]
|
|
297
|
-
);
|
|
298
|
-
} finally {
|
|
299
|
-
await client.end();
|
|
300
|
-
}
|
|
764
|
+
### MongoDB Schema
|
|
765
|
+
|
|
766
|
+
For MongoDB, no manual schema creation is required. The SDK will create documents with this structure:
|
|
767
|
+
|
|
768
|
+
```javascript
|
|
769
|
+
{
|
|
770
|
+
app_id: "default",
|
|
771
|
+
tokens: {
|
|
772
|
+
access_token: "...",
|
|
773
|
+
refresh_token: "...",
|
|
774
|
+
expires_at: "2025-01-01T00:00:00.000Z",
|
|
775
|
+
expires_in: 3600
|
|
301
776
|
}
|
|
302
777
|
}
|
|
303
778
|
```
|
|
304
779
|
|
|
305
|
-
|
|
780
|
+
- The collection name is configurable (default: `oauth_tokens`)
|
|
781
|
+
- A unique index on `app_id` is automatically created
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
### Example: Using DatabaseTokenStorage
|
|
786
|
+
|
|
787
|
+
> **Note:** You can use local or cloud database connection strings (for example, Heroku Postgres, MongoDB Atlas, etc.) in all examples below.
|
|
306
788
|
|
|
307
789
|
```javascript
|
|
308
790
|
import { DatabaseTokenStorage } from "lightspeed-retail-sdk";
|
|
309
|
-
import { MongoClient } from "mongodb";
|
|
310
|
-
|
|
311
|
-
class MongoTokenStorage extends DatabaseTokenStorage {
|
|
312
|
-
constructor(connectionString, databaseName, userId) {
|
|
313
|
-
super();
|
|
314
|
-
this.connectionString = connectionString;
|
|
315
|
-
this.databaseName = databaseName;
|
|
316
|
-
this.userId = userId;
|
|
317
|
-
}
|
|
318
791
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const doc = await collection.findOne({ userId: this.userId });
|
|
328
|
-
|
|
329
|
-
if (!doc) {
|
|
330
|
-
return { access_token: null, refresh_token: null, expires_at: null };
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return {
|
|
334
|
-
access_token: doc.access_token,
|
|
335
|
-
refresh_token: doc.refresh_token,
|
|
336
|
-
expires_at: doc.expires_at,
|
|
337
|
-
};
|
|
338
|
-
} finally {
|
|
339
|
-
await client.close();
|
|
340
|
-
}
|
|
792
|
+
// PostgreSQL
|
|
793
|
+
const pgStorage = new DatabaseTokenStorage(
|
|
794
|
+
"postgres://user:pass@host:5432/dbname",
|
|
795
|
+
{
|
|
796
|
+
dbType: "postgres",
|
|
797
|
+
tableName: "oauth_tokens", // optional
|
|
798
|
+
appId: "default", // optional
|
|
341
799
|
}
|
|
800
|
+
);
|
|
342
801
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
expires_at: tokens.expires_at,
|
|
358
|
-
updated_at: new Date(),
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
{ upsert: true }
|
|
362
|
-
);
|
|
363
|
-
} finally {
|
|
364
|
-
await client.close();
|
|
365
|
-
}
|
|
802
|
+
// SQLite
|
|
803
|
+
const sqliteStorage = new DatabaseTokenStorage("./tokens.sqlite", {
|
|
804
|
+
dbType: "sqlite",
|
|
805
|
+
tableName: "oauth_tokens", // optional
|
|
806
|
+
appId: "default", // optional
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
// MongoDB
|
|
810
|
+
const mongoStorage = new DatabaseTokenStorage(
|
|
811
|
+
"mongodb://localhost:27017/yourdb",
|
|
812
|
+
{
|
|
813
|
+
dbType: "mongodb",
|
|
814
|
+
tableName: "oauth_tokens", // optional (collection name)
|
|
815
|
+
appId: "default", // optional
|
|
366
816
|
}
|
|
367
|
-
|
|
817
|
+
);
|
|
368
818
|
```
|
|
369
819
|
|
|
370
|
-
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
### Notes
|
|
823
|
+
|
|
824
|
+
- **You must create the table or collection before using the SDK.** The SDK does not auto-create tables or collections.
|
|
825
|
+
- For multi-tenant or multi-app setups, use a unique `appId` for each logical app.
|
|
826
|
+
- The SDK stores the entire token object (including access, refresh, and expiry) in the `tokens` field.
|
|
827
|
+
- For MongoDB, you may use any database name in your connection string; the collection name is configurable.
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
### Custom Storage Interface (Advanced)
|
|
832
|
+
|
|
833
|
+
> **Note:** Most users do not need to implement a custom storage backend. This is only for advanced use cases where you need to integrate with a non-standard storage system (for example, a custom API, key-value store, or enterprise secrets manager).
|
|
371
834
|
|
|
372
|
-
|
|
835
|
+
To implement your own storage, create a class with these asynchronous methods:
|
|
373
836
|
|
|
374
837
|
```javascript
|
|
375
838
|
class CustomTokenStorage {
|
|
376
839
|
async getTokens() {
|
|
377
|
-
// Return an object
|
|
378
|
-
// Return null
|
|
840
|
+
// Return an object: { access_token, refresh_token, expires_at }
|
|
841
|
+
// Return null if no tokens are stored
|
|
379
842
|
}
|
|
380
843
|
|
|
381
844
|
async setTokens(tokens) {
|
|
@@ -384,36 +847,6 @@ class CustomTokenStorage {
|
|
|
384
847
|
}
|
|
385
848
|
```
|
|
386
849
|
|
|
387
|
-
### Database Schema Examples
|
|
388
|
-
|
|
389
|
-
#### MySQL/PostgreSQL Schema
|
|
390
|
-
|
|
391
|
-
```sql
|
|
392
|
-
CREATE TABLE user_tokens (
|
|
393
|
-
user_id VARCHAR(255) PRIMARY KEY,
|
|
394
|
-
access_token TEXT NOT NULL,
|
|
395
|
-
refresh_token TEXT NOT NULL,
|
|
396
|
-
expires_at TIMESTAMP NOT NULL,
|
|
397
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
398
|
-
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
399
|
-
);
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
#### MongoDB Schema
|
|
403
|
-
|
|
404
|
-
```javascript
|
|
405
|
-
// No strict schema required, but documents will look like:
|
|
406
|
-
{
|
|
407
|
-
_id: ObjectId("..."),
|
|
408
|
-
userId: "user123",
|
|
409
|
-
access_token: "eyJ0eXAiOiJKV1Q...",
|
|
410
|
-
refresh_token: "def5020058aac34d...",
|
|
411
|
-
expires_at: "2025-07-02T16:09:42.069Z",
|
|
412
|
-
created_at: ISODate("2025-07-02T15:09:42.069Z"),
|
|
413
|
-
updated_at: ISODate("2025-07-02T15:09:42.069Z")
|
|
414
|
-
}
|
|
415
|
-
```
|
|
416
|
-
|
|
417
850
|
## CommonJS Usage
|
|
418
851
|
|
|
419
852
|
The SDK supports both ES modules and CommonJS:
|
|
@@ -444,16 +877,60 @@ If you're upgrading from a previous version:
|
|
|
444
877
|
1. **Update your refresh token** by making one call to the new OAuth endpoint
|
|
445
878
|
2. **Implement token storage** to persist the rotating tokens
|
|
446
879
|
3. **Update token URLs** (handled automatically by the SDK)
|
|
447
|
-
4. **Ensure storage can handle longer tokens** (new tokens are significantly longer)
|
|
880
|
+
4. **Ensure your storage can handle longer tokens** (new tokens are significantly longer)
|
|
448
881
|
|
|
449
882
|
## API Methods
|
|
450
883
|
|
|
884
|
+
### Enhanced Parameter Support
|
|
885
|
+
|
|
886
|
+
**All main getter methods now support both legacy and new object-based parameters:**
|
|
887
|
+
|
|
888
|
+
#### Legacy Parameter Syntax (Still Supported)
|
|
889
|
+
|
|
890
|
+
```javascript
|
|
891
|
+
const customers = await api.getCustomers("Contact");
|
|
892
|
+
const items = await api.getItems("Category,Vendor", 50);
|
|
893
|
+
const sales = await api.getSales("Customer", 25);
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
#### New Object-Based Parameter Syntax
|
|
897
|
+
|
|
898
|
+
```javascript
|
|
899
|
+
const customers = await api.getCustomers({
|
|
900
|
+
relations: "Contact",
|
|
901
|
+
limit: 50,
|
|
902
|
+
timeStamp: "2025-07-07T10:00:00.000Z",
|
|
903
|
+
sort: "timeStamp",
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
const items = await api.getItems({
|
|
907
|
+
relations: "Category,Vendor",
|
|
908
|
+
limit: 25,
|
|
909
|
+
timeStamp: "2025-07-07T10:00:00.000Z",
|
|
910
|
+
sort: "description",
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
const sales = await api.getSales({
|
|
914
|
+
relations: "Customer",
|
|
915
|
+
limit: 100,
|
|
916
|
+
timeStamp: "2025-07-07T10:00:00.000Z",
|
|
917
|
+
sort: "timeStamp",
|
|
918
|
+
});
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
#### Available Parameters
|
|
922
|
+
|
|
923
|
+
- **relations**: Load related data (e.g., 'Category,Vendor')
|
|
924
|
+
- **limit**: Limit number of results (max 100) - triggers single-page request
|
|
925
|
+
- **timeStamp**: Filter by timestamp (ISO format) - retrieves records updated since this time
|
|
926
|
+
- **sort**: Sort results by field (e.g., 'timeStamp', 'description')
|
|
927
|
+
|
|
451
928
|
### Core Resources
|
|
452
929
|
|
|
453
930
|
#### Customers
|
|
454
931
|
|
|
455
932
|
- `getCustomer(id, relations)` - Fetch a specific customer by ID
|
|
456
|
-
- `getCustomers(
|
|
933
|
+
- `getCustomers(params)` - Retrieve all customers ✨ **Enhanced with object parameters**
|
|
457
934
|
- `putCustomer(id, data)` - Update a customer
|
|
458
935
|
- `postCustomer(data)` - Create a new customer
|
|
459
936
|
- `searchCustomers(searchTerm, relations)` - Search customers by name or email
|
|
@@ -461,57 +938,74 @@ If you're upgrading from a previous version:
|
|
|
461
938
|
#### Items
|
|
462
939
|
|
|
463
940
|
- `getItem(id, relations)` - Fetch a specific item by ID
|
|
464
|
-
- `getItems(
|
|
941
|
+
- `getItems(params)` - Retrieve all items ✨ **Enhanced with object parameters**
|
|
465
942
|
- `getMultipleItems(items, relations)` - Get multiple items by IDs
|
|
466
943
|
- `putItem(id, data)` - Update an item
|
|
467
944
|
- `postItem(data)` - Create a new item
|
|
468
945
|
- `getVendorItems(vendorID, relations)` - Get items by vendor
|
|
469
946
|
- `searchItems(searchTerm, relations)` - Search items by description
|
|
470
|
-
- `getItemsByCategory(
|
|
471
|
-
- `getItemsWithLowStock(
|
|
947
|
+
- `getItemsByCategory(params)` - Get items in a category ✨ **Enhanced with object parameters**
|
|
948
|
+
- `getItemsWithLowStock(params)` - Get items below stock threshold ✨ **Enhanced with object parameters**
|
|
472
949
|
- `updateMultipleItems(updates)` - Bulk update multiple items
|
|
473
950
|
|
|
951
|
+
**Enhanced getItems Examples:**
|
|
952
|
+
|
|
953
|
+
```javascript
|
|
954
|
+
// Legacy usage (still works)
|
|
955
|
+
const items = await api.getItems("Category,Vendor", 50);
|
|
956
|
+
|
|
957
|
+
// New object-based usage with timestamp filtering
|
|
958
|
+
const recentItems = await api.getItems({
|
|
959
|
+
timeStamp: "2025-07-07T10:00:00.000Z", // Items updated since this timestamp
|
|
960
|
+
relations: "Category,Vendor",
|
|
961
|
+
sort: "timeStamp",
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
// Basic usage with relations only
|
|
965
|
+
const itemsWithCategories = await api.getItems({ relations: "Category" });
|
|
966
|
+
```
|
|
967
|
+
|
|
474
968
|
#### Matrix Items
|
|
475
969
|
|
|
476
970
|
- `getMatrixItem(id, relations)` - Fetch a specific matrix item by ID
|
|
477
|
-
- `getMatrixItems(
|
|
971
|
+
- `getMatrixItems(params)` - Retrieve all matrix items ✨ **Enhanced with object parameters**
|
|
478
972
|
- `putMatrixItem(id, data)` - Update a matrix item
|
|
479
973
|
- `postMatrixItem(data)` - Create a new matrix item
|
|
480
974
|
|
|
481
975
|
#### Categories
|
|
482
976
|
|
|
483
977
|
- `getCategory(id, relations)` - Fetch a specific category by ID
|
|
484
|
-
- `getCategories(
|
|
978
|
+
- `getCategories(params)` - Retrieve all categories ✨ **Enhanced with object parameters**
|
|
485
979
|
- `putCategory(id, data)` - Update a category
|
|
486
980
|
- `postCategory(data)` - Create a new category
|
|
487
981
|
|
|
488
982
|
#### Manufacturers
|
|
489
983
|
|
|
490
984
|
- `getManufacturer(id, relations)` - Fetch a specific manufacturer by ID
|
|
491
|
-
- `getManufacturers(
|
|
985
|
+
- `getManufacturers(params)` - Retrieve all manufacturers ✨ **Enhanced with object parameters**
|
|
492
986
|
- `putManufacturer(id, data)` - Update a manufacturer
|
|
493
987
|
- `postManufacturer(data)` - Create a new manufacturer
|
|
494
988
|
|
|
495
989
|
#### Vendors
|
|
496
990
|
|
|
497
991
|
- `getVendor(id, relations)` - Fetch a specific vendor by ID
|
|
498
|
-
- `getVendors(
|
|
992
|
+
- `getVendors(params)` - Retrieve all vendors ✨ **Enhanced with object parameters**
|
|
499
993
|
- `putVendor(id, data)` - Update a vendor
|
|
500
994
|
- `postVendor(data)` - Create a new vendor
|
|
501
995
|
|
|
502
996
|
#### Orders
|
|
503
997
|
|
|
504
998
|
- `getOrder(id, relations)` - Fetch a specific order by ID
|
|
505
|
-
- `getOrders(
|
|
999
|
+
- `getOrders(params)` - Retrieve all orders ✨ **Enhanced with object parameters**
|
|
506
1000
|
- `getOrdersByVendorID(id, relations)` - Get orders by vendor
|
|
507
1001
|
- `getOpenOrdersByVendorID(id, relations)` - Get open orders by vendor
|
|
508
1002
|
|
|
509
1003
|
#### Sales
|
|
510
1004
|
|
|
511
1005
|
- `getSale(id, relations)` - Fetch a specific sale by ID
|
|
512
|
-
- `getSales(
|
|
1006
|
+
- `getSales(params)` - Retrieve all sales ✨ **Enhanced with object parameters**
|
|
513
1007
|
- `getMultipleSales(saleIDs, relations)` - Get multiple sales by IDs
|
|
514
|
-
- `getSalesByDateRange(
|
|
1008
|
+
- `getSalesByDateRange(params)` - Get sales in date range ✨ **Enhanced with object parameters**
|
|
515
1009
|
- `putSale(id, data)` - Update a sale
|
|
516
1010
|
- `postSale(data)` - Create a new sale
|
|
517
1011
|
|
|
@@ -529,26 +1023,26 @@ If you're upgrading from a previous version:
|
|
|
529
1023
|
|
|
530
1024
|
#### Employees
|
|
531
1025
|
|
|
532
|
-
- `getEmployees(
|
|
1026
|
+
- `getEmployees(params)` - Get all employees ✨ **Enhanced with object parameters**
|
|
533
1027
|
- `getEmployee(id, relations)` - Get a specific employee
|
|
534
1028
|
|
|
535
1029
|
#### System Configuration
|
|
536
1030
|
|
|
537
|
-
- `getCustomerTypes(
|
|
538
|
-
- `getRegisters(
|
|
539
|
-
- `getPaymentTypes(
|
|
540
|
-
- `getTaxClasses(
|
|
541
|
-
- `getItemAttributes(
|
|
1031
|
+
- `getCustomerTypes(params)` - Get customer types ✨ **Enhanced with object parameters**
|
|
1032
|
+
- `getRegisters(params)` - Get registers/shops ✨ **Enhanced with object parameters**
|
|
1033
|
+
- `getPaymentTypes(params)` - Get payment types ✨ **Enhanced with object parameters**
|
|
1034
|
+
- `getTaxClasses(params)` - Get tax classes ✨ **Enhanced with object parameters**
|
|
1035
|
+
- `getItemAttributes(params)` - Get item attributes ✨ **Enhanced with object parameters**
|
|
542
1036
|
|
|
543
1037
|
### Gift Cards & Special Orders
|
|
544
1038
|
|
|
545
|
-
- `getGiftCards(
|
|
1039
|
+
- `getGiftCards(params)` - Get all gift cards ✨ **Enhanced with object parameters**
|
|
546
1040
|
- `getGiftCard(id, relations)` - Get a specific gift card by code
|
|
547
|
-
- `getSpecialOrders(
|
|
1041
|
+
- `getSpecialOrders(params)` - Get special orders ✨ **Enhanced with object parameters**
|
|
548
1042
|
|
|
549
1043
|
### Images
|
|
550
1044
|
|
|
551
|
-
- `getImages(
|
|
1045
|
+
- `getImages(params)` - Get all images ✨ **Enhanced with object parameters**
|
|
552
1046
|
- `postImage(imageFilePath, metadata)` - Upload an image
|
|
553
1047
|
|
|
554
1048
|
### Utility Methods
|
|
@@ -559,18 +1053,54 @@ If you're upgrading from a previous version:
|
|
|
559
1053
|
|
|
560
1054
|
## Error Handling
|
|
561
1055
|
|
|
562
|
-
The SDK includes comprehensive error handling with automatic retries for transient failures:
|
|
1056
|
+
The SDK includes comprehensive error handling with automatic retries for transient failures and robust safety guarantees:
|
|
1057
|
+
|
|
1058
|
+
### **Automatic Error Recovery**
|
|
1059
|
+
|
|
1060
|
+
- **Retry Logic**: Automatic retries for network errors and 5xx server errors
|
|
1061
|
+
- **401 Handling**: Automatic token refresh and request retry on authentication failures
|
|
1062
|
+
- **Rate Limiting**: Intelligent delays when approaching API rate limits
|
|
1063
|
+
|
|
1064
|
+
### **Safe Return Types**
|
|
1065
|
+
|
|
1066
|
+
All GET methods are guaranteed to return consistent data types, never `undefined`:
|
|
563
1067
|
|
|
564
1068
|
```javascript
|
|
565
1069
|
try {
|
|
566
|
-
|
|
567
|
-
|
|
1070
|
+
// These methods ALWAYS return arrays (never undefined)
|
|
1071
|
+
const items = await api.getItems({ timeStamp: "2025-07-07T10:00:00Z" });
|
|
1072
|
+
const customers = await api.getCustomers();
|
|
1073
|
+
const categories = await api.getCategories();
|
|
1074
|
+
|
|
1075
|
+
// Safe to access array properties without checking for undefined
|
|
1076
|
+
console.log(`Found ${items.length} items`);
|
|
1077
|
+
|
|
1078
|
+
// Even on API errors, you get an empty array
|
|
1079
|
+
if (items.length === 0) {
|
|
1080
|
+
console.log("No items found or API error occurred");
|
|
1081
|
+
}
|
|
568
1082
|
} catch (error) {
|
|
569
|
-
console.error("
|
|
570
|
-
//
|
|
1083
|
+
console.error("SDK Error:", error.message);
|
|
1084
|
+
// Detailed error logging is handled automatically by the SDK
|
|
571
1085
|
}
|
|
572
1086
|
```
|
|
573
1087
|
|
|
1088
|
+
### **Enhanced Error Logging**
|
|
1089
|
+
|
|
1090
|
+
When errors occur, the SDK provides detailed logging including:
|
|
1091
|
+
|
|
1092
|
+
- Request URLs and parameters
|
|
1093
|
+
- HTTP status codes and response data
|
|
1094
|
+
- Helpful context for debugging
|
|
1095
|
+
- Email notifications (when configured) for token refresh failures
|
|
1096
|
+
|
|
1097
|
+
### **Graceful Degradation**
|
|
1098
|
+
|
|
1099
|
+
- API errors don't crash your application
|
|
1100
|
+
- Empty arrays returned instead of undefined
|
|
1101
|
+
- Detailed error messages logged for debugging
|
|
1102
|
+
- Automatic fallback behavior for common scenarios
|
|
1103
|
+
|
|
574
1104
|
## Rate Limiting
|
|
575
1105
|
|
|
576
1106
|
The SDK automatically handles Lightspeed's API rate limits by:
|