@liquidcommerce/elements-sdk 2.2.2 → 2.3.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.
Files changed (51) hide show
  1. package/README.md +1608 -557
  2. package/dist/index.esm.js +9741 -8030
  3. package/dist/types/core/auth.service.d.ts +10 -4
  4. package/dist/types/core/base-component.service.d.ts +3 -0
  5. package/dist/types/core/circuit-breaker.service.d.ts +54 -0
  6. package/dist/types/core/client/client-action.service.d.ts +13 -11
  7. package/dist/types/core/client/client-config.service.d.ts +5 -3
  8. package/dist/types/core/command/common-command.service.d.ts +2 -1
  9. package/dist/types/core/debug-panel/debug-panel.service.d.ts +43 -0
  10. package/dist/types/core/debug-panel/debug-panel.styles.d.ts +1 -0
  11. package/dist/types/core/fingerprint.service.d.ts +4 -9
  12. package/dist/types/core/google-tag-manager.service.d.ts +126 -2
  13. package/dist/types/core/logger/logger-factory.d.ts +3 -0
  14. package/dist/types/core/logger/logger.service.d.ts +8 -5
  15. package/dist/types/core/pubsub/interfaces/core.interface.d.ts +2 -3
  16. package/dist/types/core/pubsub/interfaces/product.interface.d.ts +0 -5
  17. package/dist/types/core/store/interfaces/cart.interface.d.ts +0 -1
  18. package/dist/types/core/store/interfaces/checkout.interface.d.ts +0 -1
  19. package/dist/types/core/store/interfaces/core.interface.d.ts +2 -2
  20. package/dist/types/core/store/interfaces/product.interface.d.ts +0 -1
  21. package/dist/types/core/store/store.service.d.ts +1 -0
  22. package/dist/types/core/telemetry/telemetry.interface.d.ts +80 -0
  23. package/dist/types/core/telemetry/telemetry.service.d.ts +27 -0
  24. package/dist/types/enums/core.enum.d.ts +0 -1
  25. package/dist/types/enums/debug.enum.d.ts +6 -0
  26. package/dist/types/enums/index.d.ts +1 -0
  27. package/dist/types/interfaces/core.interface.d.ts +2 -2
  28. package/dist/types/modules/address/address.command.d.ts +1 -3
  29. package/dist/types/modules/cart/cart.commands.d.ts +1 -1
  30. package/dist/types/modules/cart/cart.component.d.ts +1 -2
  31. package/dist/types/modules/cart/components/cart-item.component.d.ts +1 -6
  32. package/dist/types/modules/checkout/checkout.commands.d.ts +3 -2
  33. package/dist/types/modules/checkout/checkout.component.d.ts +1 -2
  34. package/dist/types/modules/checkout/components/information/checkout-delivery-information-form.component.d.ts +1 -1
  35. package/dist/types/modules/checkout/components/summary/checkout-item-quantity.component.d.ts +0 -2
  36. package/dist/types/modules/checkout/components/summary/checkout-item.component.d.ts +2 -1
  37. package/dist/types/modules/checkout/components/summary/checkout-place-order-button.component.d.ts +0 -1
  38. package/dist/types/modules/checkout/constant.d.ts +0 -1
  39. package/dist/types/modules/product/components/index.d.ts +1 -0
  40. package/dist/types/modules/product/components/product-add-to-cart-section.component.d.ts +1 -0
  41. package/dist/types/modules/product/components/product-interactions.component.d.ts +4 -1
  42. package/dist/types/modules/product/components/product-price.component.d.ts +1 -0
  43. package/dist/types/modules/product/components/product-retailers.component.d.ts +1 -0
  44. package/dist/types/modules/product/product.commands.d.ts +1 -1
  45. package/dist/types/modules/ui-components/engraving/engraving-form.component.d.ts +13 -11
  46. package/dist/types/modules/ui-components/engraving/engraving-view.component.d.ts +3 -9
  47. package/dist/types/static/icon/index.d.ts +0 -1
  48. package/dist/types/utils/format.d.ts +2 -1
  49. package/package.json +12 -15
  50. package/umd/elements.js +1 -1
  51. package/dist/types/static/icon/completed.icon.d.ts +0 -2
package/README.md CHANGED
@@ -28,48 +28,20 @@ Elements SDK
28
28
  <summary>Click to expand</summary>
29
29
 
30
30
  - [Overview](#-overview)
31
- - [Latest Features](#-latest-features)
32
- - [Key Features](#-key-features)
33
- - [Architecture](#-architecture)
34
- - [System Architecture](#system-architecture)
35
- - [Component Architecture](#component-architecture)
36
- - [Event Flow](#event-flow)
37
- - [Features](#-features)
38
- - [Installation](#-installation)
39
- - [CDN Usage](#option-a--use-the-cdn)
40
- - [NPM Installation](#option-b--install-from-npm)
41
- - [Browser Support](#-browser-support)
42
31
  - [Quick Start](#-quick-start)
43
- - [Auto-initialization](#step-1--auto-initialization-easiest)
44
- - [Product Mapping](#step-2--map-products-to-containers)
45
- - [Programmatic Control](#step-3--programmatic-control-advanced)
32
+ - [Advanced Usage](#-advanced-usage)
33
+ - [Browser Support](#-browser-support)
34
+ - [Configuration](#-configuration)
46
35
  - [SDK Methods & API](#-sdk-methods--api)
47
- - [Core Client Methods](#core-client-methods)
48
- - [UI Methods](#ui-methods)
49
- - [Builder Methods](#builder-methods-development-mode)
50
36
  - [Actions](#-actions)
51
- - [Product Actions](#product-actions)
52
- - [Address Actions](#address-actions)
53
- - [Cart Actions](#cart-actions)
54
- - [Checkout Actions](#checkout-actions)
55
37
  - [Events](#-events)
56
- - [Event Listening](#event-listening)
57
- - [Available Events](#available-events)
58
- - [Configuration](#-configuration)
59
- - [Module Options](#module-options)
60
- - [Environment Options](#environment-options)
61
- - [Auto-init Attributes](#auto-init-data-attributes)
62
38
  - [Themes & Customization](#-themes--customization)
63
- - [Theme Configuration](#theme-configuration)
64
- - [Dynamic Updates](#dynamic-theme-updates)
39
+ - [Features Deep Dive](#-features-deep-dive)
40
+ - [Core Capabilities](#-core-capabilities)
41
+ - [Integration Patterns](#-integration-patterns)
42
+ - [Error Handling](#-error-handling)
43
+ - [Performance & Best Practices](#-performance--best-practices)
65
44
  - [Proxy Configuration](#-proxy-configuration)
66
- - [Demo Pages](#-demo-pages)
67
- - [Simple Demo](#simple-demo-demosimplehtml)
68
- - [Advanced Demo](#advanced-demo-demoadvancedhtml)
69
- - [Development Scripts](#-development-scripts)
70
- - [Build Commands](#build-commands)
71
- - [Code Quality](#code-quality-commands)
72
- - [Maintenance](#maintenance-commands)
73
45
  - [Documentation](#-documentation)
74
46
  - [Versioning](#-versioning)
75
47
  - [Support](#-support)
@@ -80,14 +52,6 @@ Elements SDK
80
52
 
81
53
  The LiquidCommerce Elements SDK is a **production-ready JavaScript library** that enables partners to seamlessly integrate product displays, shopping carts, and checkout flows into any website. Built with performance and developer experience in mind.
82
54
 
83
- ### 🆕 Latest Features
84
-
85
- - **Builder Mode**: Dynamic theme customization for development environments
86
- - **Action Feedback Events**: All actions now emit success/failure events for better UX
87
- - **Proxy Support**: Route API requests through your server to avoid ad blockers
88
- - **Enhanced CLI**: Improved development scripts with parallel builds and better error handling
89
- - **TypeScript Support**: Full TypeScript definitions for better IDE experience
90
-
91
55
  ### ✨ Key Features
92
56
 
93
57
  <table>
@@ -133,399 +97,550 @@ The LiquidCommerce Elements SDK is a **production-ready JavaScript library** tha
133
97
  </tr>
134
98
  </table>
135
99
 
136
- ## 🏗️ Architecture
137
-
138
- ### System Architecture
139
-
140
- ```mermaid
141
- graph TB
142
- subgraph "Your Website"
143
- HTML[HTML Page]
144
- JS[JavaScript]
145
- INIT[Elements SDK]
146
- end
147
-
148
- subgraph "Elements SDK Core"
149
- CLIENT[Elements Client]
150
-
151
- subgraph "Components"
152
- PROD[Product Component]
153
- CART[Cart Component]
154
- CHECK[Checkout Component]
155
- ADDR[Address Component]
156
- end
157
-
158
- subgraph "Services"
159
- ACT[Actions Service]
160
- EVT[Events Service]
161
- API[API Client]
162
- THEME[Theme Provider]
163
- end
164
-
165
- subgraph "UI Layer"
166
- BTN[Cart Button]
167
- FLOAT[Floating Cart]
168
- DISP[Live Displays]
169
- end
170
- end
171
-
172
- subgraph "LiquidCommerce API"
173
- PAPI[Products API]
174
- CAPI[Cart API]
175
- OAPI[Orders API]
176
- AAPI[Address API]
177
- end
178
-
179
- HTML --> INIT
180
- JS --> CLIENT
181
-
182
- CLIENT --> PROD
183
- CLIENT --> CART
184
- CLIENT --> CHECK
185
- CLIENT --> ADDR
186
-
187
- PROD --> API
188
- CART --> API
189
- CHECK --> API
190
- ADDR --> API
191
-
192
- API --> PAPI
193
- API --> CAPI
194
- API --> OAPI
195
- API --> AAPI
196
-
197
- ACT --> EVT
198
- CLIENT --> ACT
199
- CLIENT --> THEME
200
- ```
201
-
202
- ### Component Architecture
203
-
204
- ```mermaid
205
- graph LR
206
- subgraph "Product Component"
207
- PD[Product Display]
208
- PS[Size Selector]
209
- PQ[Quantity Control]
210
- PA[Add to Cart]
211
- end
212
-
213
- subgraph "Cart Component"
214
- CI[Cart Items]
215
- CQ[Quantity Update]
216
- CP[Promo Code]
217
- CT[Cart Total]
218
- end
219
-
220
- subgraph "Checkout Component"
221
- CS[Shipping Info]
222
- CB[Billing Info]
223
- PM[Payment Method]
224
- OS[Order Summary]
225
- end
226
-
227
- PD --> PS
228
- PS --> PQ
229
- PQ --> PA
230
-
231
- CI --> CQ
232
- CQ --> CT
233
- CP --> CT
234
-
235
- CS --> CB
236
- CB --> PM
237
- PM --> OS
238
- ```
239
-
240
- ### Event Flow
241
-
242
- ```mermaid
243
- sequenceDiagram
244
- participant User
245
- participant SDK
246
- participant Actions
247
- participant Events
248
- participant API
249
- participant Website
250
-
251
- User->>SDK: Add to Cart
252
- SDK->>Actions: cart.addProduct()
253
- Actions->>API: POST /cart/items
254
- API-->>Actions: Response
255
- Actions->>Events: Emit Success/Failure
256
- Events->>Website: lce:actions.cart_product_add_success
257
- Website->>User: Show Feedback
258
- ```
259
-
260
- ## 🚀 Features
261
-
262
- - **🎯 Auto-initialization**: Single script tag with data attributes
263
- - **📦 Zero Dependencies**: Everything bundled, no peer dependencies
264
- - **🌐 CDN Ready**: No build step required for basic usage
265
- - **⚡ Lightweight**: ~150KB minified bundle size
266
- - **🔧 Framework Agnostic**: Works with React, Vue, Angular, or vanilla JS
267
- - **📱 Responsive**: Mobile-first design approach
268
- - **♿ Accessible**: WCAG 2.1 AA compliant components
269
- - **🎨 Themeable**: Comprehensive customization system
270
- - **🔐 Secure**: PCI compliant checkout flow
271
- - **📊 Analytics Ready**: Built-in event system for tracking
272
- - **🌍 Multi-environment**: Support for dev, staging, and production
273
- - **🧪 Well Tested**: Comprehensive test coverage
274
-
275
- ## 📦 Installation
276
-
277
- ### Choose how to include the SDK
278
-
279
- - **Use our CDN** (no build step required)
280
- - **Install from NPM** (for bundlers like Vite, Webpack, etc.)
281
-
282
- ### Option A — Use the CDN
283
-
284
- Include the script on your page. Use the production or beta URL:
100
+ ## 🚀 Quick Start
285
101
 
286
- ```html
287
- <!-- Production (latest) -->
288
- <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
102
+ The fastest way to add e-commerce to your site is with **auto-initialization** - a single script tag that does everything.
289
103
 
290
- <!-- Beta (latest) -->
291
- <script src="https://assets-elements.liquidcommerce.us/all/beta/elements.js"></script>
292
- ```
104
+ ### The Simplest Setup (30 seconds)
293
105
 
294
- You can also pin to a specific version:
106
+ Add this single script tag to your page:
295
107
 
296
108
  ```html
297
- <script src="https://assets-elements.liquidcommerce.us/all/1.2.3/elements.js"></script>
109
+ <script
110
+ data-liquid-commerce-elements
111
+ data-token="YOUR_API_KEY"
112
+ data-env="production"
113
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
114
+ ></script>
298
115
  ```
299
116
 
300
- ### Option B Install from NPM
117
+ That's it! You now have:
118
+ - ✅ A floating cart button (bottom right)
119
+ - ✅ Full cart functionality
120
+ - ✅ Complete checkout flow
121
+ - ✅ Ready to add products
301
122
 
302
- ```bash
303
- npm install @liquidcommerceteam/elements-sdk
304
- # or
305
- pnpm add @liquidcommerceteam/elements-sdk
123
+ ### Adding Products to Your Page
124
+
125
+ Now let's display products. Choose the method that fits your use case:
126
+
127
+ #### Method 1: Direct Attributes (Best for static pages)
128
+
129
+ Add products directly in the script tag:
130
+
131
+ ```html
132
+ <div id="product-1"></div>
133
+ <div id="product-2"></div>
134
+
135
+ <script
136
+ data-liquid-commerce-elements
137
+ data-token="YOUR_API_KEY"
138
+ data-env="production"
139
+ data-container-1="product-1"
140
+ data-product-1="00619947000020"
141
+ data-container-2="product-2"
142
+ data-product-2="00832889005513"
143
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
144
+ ></script>
306
145
  ```
307
146
 
308
- Then import and initialize in your app code:
147
+ **Use case:** Static HTML pages with known products
309
148
 
310
- ```js
311
- import { Elements } from '@liquidcommerceteam/elements-sdk';
149
+ #### Method 2: JSON Configuration (Best for CMS/dynamic content)
312
150
 
313
- const client = await Elements('YOUR_API_KEY', {
314
- env: 'production',
315
- });
151
+ Configure products via a JSON script block:
152
+
153
+ ```html
154
+ <div id="product-1"></div>
155
+ <div id="product-2"></div>
156
+
157
+ <script data-liquid-commerce-elements-products type="application/json">
158
+ [
159
+ { "containerId": "product-1", "identifier": "00619947000020" },
160
+ { "containerId": "product-2", "identifier": "00832889005513" }
161
+ ]
162
+ </script>
163
+
164
+ <script
165
+ data-liquid-commerce-elements
166
+ data-token="YOUR_API_KEY"
167
+ data-env="production"
168
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
169
+ ></script>
316
170
  ```
317
171
 
318
- ## 🌐 Browser Support
172
+ **Use case:** CMS platforms, templating engines, server-side rendering
319
173
 
320
- ⚠️ **Important**: This SDK is designed for browser environments only. It will not work in server-side rendering, Node.js, or other non-browser environments. The SDK includes built-in safety measures to prevent errors when accidentally imported in these environments.
174
+ #### Method 3: Annotated Elements (Best for grids/lists)
321
175
 
322
- ### Supported Browsers
176
+ Mark any div with a data attribute:
323
177
 
324
- The SDK supports **2018+ browsers** with comprehensive polyfills:
178
+ ```html
179
+ <div class="product-grid">
180
+ <div data-lce-product="00619947000020"></div>
181
+ <div data-lce-product="00832889005513"></div>
182
+ <div data-lce-product="00851468007252"></div>
183
+ </div>
325
184
 
326
- | Browser | Minimum Version | Released |
327
- |---------|----------------|----------|
328
- | Chrome | 66+ | April 2018 |
329
- | Firefox | 60+ | May 2018 |
330
- | Safari | 12+ | September 2018 |
331
- | Edge | 79+ (Chromium) | January 2020 |
332
- | Samsung Internet | 7.2+ | June 2018 |
185
+ <script
186
+ data-liquid-commerce-elements
187
+ data-token="YOUR_API_KEY"
188
+ data-env="production"
189
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
190
+ ></script>
191
+ ```
333
192
 
334
- 📖 See [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) for detailed version compatibility and polyfill information.
193
+ **Use case:** Product grids, category pages, search results
335
194
 
336
- ## 🚀 Quick Start
195
+ ### Customizing the Cart Button
337
196
 
338
- ### Step 1 Auto-initialization (Easiest)
197
+ By default, you get a floating cart button. Here's how to customize it:
339
198
 
340
- This single script both loads the SDK and initializes it automatically. Place it:
341
- - At the end of the `<body>` (recommended), or
342
- - In the `<head>` with `defer` so it doesn't block rendering.
199
+ #### Option 1: Cart Button in a Specific Container
343
200
 
344
201
  ```html
345
- <!-- Body footer (recommended) -->
202
+ <nav>
203
+ <div id="header-cart"></div>
204
+ </nav>
205
+
346
206
  <script
347
207
  data-liquid-commerce-elements
348
208
  data-token="YOUR_API_KEY"
349
209
  data-env="production"
350
- data-cart-id="buttons-container"
210
+ data-cart-id="header-cart"
351
211
  data-show-cart-items
352
212
  src="https://assets-elements.liquidcommerce.us/all/elements.js"
353
213
  ></script>
214
+ ```
215
+
216
+ #### Option 2: No Cart Button (Manual Control)
354
217
 
355
- <!-- OR: Head with defer -->
218
+ ```html
356
219
  <script
357
- defer
358
220
  data-liquid-commerce-elements
359
221
  data-token="YOUR_API_KEY"
360
222
  data-env="production"
361
- data-cart-id="buttons-container"
362
- data-show-cart-items
223
+ data-hide-cart-floating-button
363
224
  src="https://assets-elements.liquidcommerce.us/all/elements.js"
364
225
  ></script>
365
226
  ```
366
227
 
367
- **Available data attributes:**
368
- - `data-token="YOUR_API_KEY"` - Your API key (required)
369
- - `data-env="production|development"` - Environment (default: production)
370
- - `data-cart-id="container-id"` - ID for cart button container (optional, creates floating button if omitted)
371
- - `data-show-cart-items` - Show items count badge on cart button (optional)
372
- - `data-enable-debugging` - Enable debug logging in development (optional)
228
+ ### Advanced Auto-Init Features
373
229
 
374
- Add containers where you want elements to render:
230
+ #### Add Product via URL (Marketing Links)
231
+
232
+ Enable "add to cart" via URL parameters for email campaigns and ads:
375
233
 
376
234
  ```html
377
- <div id="buttons-container"></div>
378
- <div id="pdp-1"></div>
379
- <div id="pdp-2"></div>
235
+ <script
236
+ data-liquid-commerce-elements
237
+ data-token="YOUR_API_KEY"
238
+ data-env="production"
239
+ data-product-param="lce_product"
240
+ data-product-fulfillment-type-param="lce_fulfillment"
241
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
242
+ ></script>
243
+ ```
244
+
245
+ Now this URL auto-adds a product to cart:
246
+ ```
247
+ https://yoursite.com/shop?lce_product=00619947000020&lce_fulfillment=shipping
380
248
  ```
381
249
 
382
- ### Step 2 Map products to containers
250
+ **Use case:** Email campaigns, social media ads, QR codes
383
251
 
384
- Choose one or combine multiple methods:
252
+ #### Apply Promo Code via URL (Campaign Tracking)
385
253
 
386
- #### 1) Attribute pairs on the main script
254
+ Auto-apply promo codes from URL parameters:
387
255
 
388
256
  ```html
389
257
  <script
390
258
  data-liquid-commerce-elements
391
259
  data-token="YOUR_API_KEY"
392
260
  data-env="production"
393
- data-container-1="pdp-1"
394
- data-product-1="00619947000020"
395
- data-container-2="pdp-2"
396
- data-product-2="00832889005513"
261
+ data-promo-code-param="lce_promo"
397
262
  src="https://assets-elements.liquidcommerce.us/all/elements.js"
398
263
  ></script>
399
264
  ```
400
265
 
401
- #### 2) JSON configuration script
266
+ Now this URL auto-applies a promo code:
267
+ ```
268
+ https://yoursite.com/shop?lce_promo=SUMMER20
269
+ ```
270
+
271
+ **Use case:** Promotional campaigns, influencer codes, affiliate links
272
+
273
+ #### Promo Ticker (Rotating Promotions)
274
+
275
+ Display rotating promotional messages:
402
276
 
403
277
  ```html
404
- <script data-liquid-commerce-elements-products type="application/json">
405
- [
406
- { "containerId": "pdp-1", "identifier": "00619947000020" },
407
- { "containerId": "pdp-2", "identifier": "00832889005513" }
408
- ]
409
- </script>
278
+ <script
279
+ data-liquid-commerce-elements
280
+ data-token="YOUR_API_KEY"
281
+ data-env="production"
282
+ data-promo-code="FREESHIP"
283
+ data-promo-text="Free Shipping Today Only!|Use code FREESHIP at checkout"
284
+ data-promo-separator="•"
285
+ data-promo-active-from="2025-01-01T00:00:00Z"
286
+ data-promo-active-until="2025-01-31T23:59:59Z"
287
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
288
+ ></script>
410
289
  ```
411
290
 
412
- #### 3) Annotated elements
291
+ **Use case:** Time-sensitive promotions, holiday sales, flash deals
292
+
293
+ #### Debug Mode (Development)
294
+
295
+ Enable debug logging during development:
413
296
 
414
297
  ```html
415
- <div data-lce-product="00619947000020"></div>
416
- <div data-lce-product="00832889005513"></div>
298
+ <script
299
+ data-liquid-commerce-elements
300
+ data-token="YOUR_API_KEY"
301
+ data-env="development"
302
+ data-debug-mode="console"
303
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
304
+ ></script>
305
+ ```
306
+
307
+ **Debug modes:**
308
+ - `console` - Logs to browser console
309
+ - `panel` - Shows visual debug panel + console logs
310
+ - Not set - No debugging (production default)
311
+
312
+ ### Complete Auto-Init Reference
313
+
314
+ Here's every available data attribute:
315
+
316
+ ```html
317
+ <script
318
+ data-liquid-commerce-elements
319
+
320
+ <!-- Required -->
321
+ data-token="YOUR_API_KEY"
322
+
323
+ <!-- Environment -->
324
+ data-env="production|staging|development|local"
325
+
326
+ <!-- Cart Button -->
327
+ data-cart-id="container-id"
328
+ data-show-cart-items
329
+ data-hide-cart-floating-button
330
+
331
+ <!-- Products (Method 1: Direct) -->
332
+ data-container-1="div-id"
333
+ data-product-1="identifier"
334
+ data-container-2="div-id"
335
+ data-product-2="identifier"
336
+
337
+ <!-- URL Parameters -->
338
+ data-product-param="lce_product"
339
+ data-product-fulfillment-type-param="lce_fulfillment"
340
+ data-promo-code-param="lce_promo"
341
+
342
+ <!-- Promo Ticker -->
343
+ data-promo-code="CODE"
344
+ data-promo-text="Message 1|Message 2"
345
+ data-promo-separator="•"
346
+ data-promo-active-from="2025-01-01T00:00:00Z"
347
+ data-promo-active-until="2025-12-31T23:59:59Z"
348
+
349
+ <!-- Debugging (dev only) -->
350
+ data-debug-mode="console|panel"
351
+
352
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
353
+ ></script>
417
354
  ```
418
355
 
419
- ### Step 3 Programmatic Control (Advanced)
356
+ **📖 For complete auto-init options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for all data attributes and configuration details.
420
357
 
421
- Initialize the SDK yourself for full control:
358
+ ---
359
+
360
+ ## 🔧 Advanced Usage
361
+
362
+ Need more control? Initialize programmatically for full access to the SDK API.
363
+
364
+ ### Installation
365
+
366
+ **CDN:**
367
+ ```html
368
+ <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
369
+
370
+ <!-- Pin to specific version: -->
371
+ <script src="https://assets-elements.liquidcommerce.us/all/1.2.3/elements.js"></script>
372
+ ```
373
+
374
+ **NPM:**
375
+ ```bash
376
+ npm install @liquidcommerce/elements-sdk
377
+ # or
378
+ pnpm add @liquidcommerce/elements-sdk
379
+ ```
380
+
381
+ ### Programmatic Initialization
422
382
 
423
383
  ```html
424
384
  <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
425
385
  <script>
426
- (async () => {
427
- const client = await window.Elements('YOUR_API_KEY', {
428
- env: 'production',
429
- enableDebugging: false, // only for development
430
- customTheme: { /* optional theming overrides */ }
431
- });
386
+ (async () => {
387
+ const client = await window.Elements('YOUR_API_KEY', {
388
+ env: 'production',
389
+ debugMode: 'none',
390
+ customTheme: { /* theming overrides */ },
391
+ proxy: { /* proxy config */ }
392
+ });
432
393
 
433
- // Your implementation here...
434
- })();
394
+ // Inject components
395
+ await client.injectProductElement([
396
+ { containerId: 'pdp-1', identifier: '00619947000020' }
397
+ ]);
398
+
399
+ // Create cart button
400
+ client.ui.cartButton('cart-container', true);
401
+
402
+ // Use actions API
403
+ await client.actions.cart.addProduct([{
404
+ identifier: '00619947000020',
405
+ fulfillmentType: 'shipping',
406
+ quantity: 1
407
+ }]);
408
+ })();
435
409
  </script>
436
410
  ```
437
411
 
438
- ## 📖 SDK Methods & API
412
+ **NPM Import:**
413
+ ```js
414
+ import { Elements } from '@liquidcommerce/elements-sdk';
415
+
416
+ const client = await Elements('YOUR_API_KEY', { env: 'production' });
417
+ ```
418
+
419
+ ---
420
+
421
+ ## 🌐 Browser Support
422
+
423
+ ⚠️ **Important**: This SDK is designed for browser environments only. It will not work in server-side rendering, Node.js, or other non-browser environments.
439
424
 
440
- ### Core Client Methods
425
+ ### Supported Browsers (2018+)
441
426
 
442
- Once initialized, the client provides these core methods:
427
+ | Browser | Minimum Version | Released |
428
+ |---------|----------------|----------|
429
+ | Chrome | 66+ | April 2018 |
430
+ | Firefox | 60+ | May 2018 |
431
+ | Safari | 12+ | September 2018 |
432
+ | Edge | 79+ (Chromium) | January 2020 |
433
+ | Samsung Internet | 7.2+ | June 2018 |
443
434
 
444
- #### Product Injection
435
+ 📖 See [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) for detailed compatibility.
445
436
 
446
- **`injectProductElement(params: IInjectProductElement[]): Promise<void>`**
437
+ ## ⚙️ Configuration
447
438
 
448
- Inject product components into containers:
439
+ ### Basic Configuration
449
440
 
450
441
  ```js
451
- await client.injectProductElement([
452
- { containerId: 'pdp-1', identifier: '00619947000020' },
453
- { containerId: 'pdp-2', identifier: '00832889005513' }
454
- ]);
442
+ const client = await Elements('YOUR_API_KEY', {
443
+ env: 'production', // Environment
444
+ debugMode: 'none', // Debug mode
445
+ customTheme: { }, // Theme overrides
446
+ proxy: { }, // Proxy configuration
447
+ promoTicker: [ ] // Promotional messages
448
+ });
455
449
  ```
456
450
 
457
- #### Cart Injection
451
+ ### Environment Options
458
452
 
459
- **`injectCartElement(containerId: string): Promise<void>`**
453
+ ```js
454
+ env: 'production' // Live environment (default)
455
+ env: 'staging' // Pre-production testing
456
+ env: 'development' // Development with extra logging
457
+ env: 'local' // Local development
458
+ ```
460
459
 
461
- Inject a cart component:
460
+ ### Debug Modes
462
461
 
463
462
  ```js
464
- await client.injectCartElement('cart-container');
463
+ debugMode: 'none' // No debugging (production default)
464
+ debugMode: 'console' // Console logs only
465
+ debugMode: 'panel' // Visual debug panel + console logs
465
466
  ```
466
467
 
467
- #### Checkout Injection
468
+ **Note:** Debug mode is automatically disabled in production environment for security.
468
469
 
469
- **`injectCheckoutElement(containerId: string): Promise<void>`**
470
+ ### Custom Theme
470
471
 
471
- Inject a checkout component:
472
+ Override default styles and layouts:
472
473
 
473
474
  ```js
474
- await client.injectCheckoutElement('checkout-container');
475
+ customTheme: {
476
+ global: {
477
+ theme: {
478
+ primaryColor: '#007bff',
479
+ accentColor: '#6c757d',
480
+ successColor: '#28a745',
481
+ errorColor: '#dc3545',
482
+ buttonCornerRadius: '8px',
483
+ cardCornerRadius: '12px',
484
+ headingFont: {
485
+ name: 'Inter',
486
+ weights: [600, 700]
487
+ },
488
+ paragraphFont: {
489
+ name: 'Inter',
490
+ weights: [400, 500]
491
+ }
492
+ },
493
+ layout: {
494
+ allowPromoCodes: true,
495
+ inputFieldStyle: 'outlined'
496
+ }
497
+ },
498
+ product: {
499
+ layout: {
500
+ showDescription: true,
501
+ addToCartButtonText: 'Add to Cart',
502
+ fulfillmentDisplay: 'carousel'
503
+ }
504
+ },
505
+ cart: {
506
+ layout: {
507
+ showQuantityCounter: true,
508
+ drawerHeaderText: 'Your Cart'
509
+ }
510
+ },
511
+ checkout: {
512
+ layout: {
513
+ allowGiftCards: true,
514
+ emailOptIn: { show: true, checked: false, text: 'Email me with news' },
515
+ smsOptIn: { show: true, checked: false, text: 'Text me with updates' }
516
+ }
517
+ }
518
+ }
475
519
  ```
476
520
 
477
- #### Address Injection
521
+ **📖 For complete theming options:** See [`docs/THEMING.md`](docs/THEMING.md)
478
522
 
479
- **`injectAddressElement(containerId: string): Promise<void>`**
523
+ ### Proxy Configuration
480
524
 
481
- Inject an address form component:
525
+ Route API requests through your server to avoid ad blockers:
482
526
 
483
527
  ```js
484
- await client.injectAddressElement('address-container');
528
+ proxy: {
529
+ baseUrl: 'https://yourdomain.com/api/proxy',
530
+ headers: {
531
+ 'X-Custom-Auth': 'your-token'
532
+ }
533
+ }
534
+ ```
535
+
536
+ See [`docs/PROXY.md`](docs/PROXY.md) for implementation guide.
537
+
538
+ ### Promo Ticker
539
+
540
+ Display rotating promotional messages:
541
+
542
+ ```js
543
+ promoTicker: [
544
+ {
545
+ promoCode: 'FREESHIP',
546
+ text: ['Free Shipping Today!', 'Use code FREESHIP'],
547
+ separator: '•',
548
+ activeFrom: '2025-01-01T00:00:00Z',
549
+ activeUntil: '2025-12-31T23:59:59Z'
550
+ }
551
+ ]
485
552
  ```
486
553
 
487
- ### UI Methods
554
+ **📖 For all configuration options:** See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for complete reference with TypeScript types.
555
+
556
+ ---
557
+
558
+ ## 📖 SDK Methods & API
559
+
560
+ ### Component Injection
488
561
 
489
- #### Cart Buttons
562
+ Inject SDK components into your page containers.
563
+
564
+ #### Products
565
+
566
+ ```js
567
+ await client.injectProductElement([
568
+ { containerId: 'pdp-1', identifier: '00619947000020' },
569
+ { containerId: 'pdp-2', identifier: '00832889005513' }
570
+ ]);
571
+ ```
490
572
 
491
- **`ui.cartButton(containerId: string, showItemsCount?: boolean): void`**
573
+ **Identifier types:** UPC, product ID, or Salsify grouping ID
492
574
 
493
- Create an "open cart" button in a specific container:
575
+ #### Cart
494
576
 
495
577
  ```js
496
- client.ui.cartButton('buttons-container');
578
+ await client.injectCartElement('cart-container');
579
+ ```
580
+
581
+ **Use case:** Dedicated cart page
582
+
583
+ #### Checkout
497
584
 
498
- // With items count badge
499
- client.ui.cartButton('buttons-container', true);
585
+ ```js
586
+ await client.injectCheckoutElement('checkout-container');
500
587
  ```
501
588
 
502
- **`ui.floatingCartButton(showItemsCount?: boolean): void`**
589
+ **Use case:** Dedicated checkout page
503
590
 
504
- Automatically inject a floating cart button:
591
+ #### Address
505
592
 
506
593
  ```js
507
- client.ui.floatingCartButton();
594
+ await client.injectAddressElement('address-container');
595
+ ```
508
596
 
509
- // With items count badge
510
- client.ui.floatingCartButton(true);
597
+ **Use case:** Shipping address collection page
598
+
599
+ ### UI Helpers
600
+
601
+ Create standalone UI elements that integrate with the SDK.
602
+
603
+ #### Cart Button (in container)
604
+
605
+ ```js
606
+ client.ui.cartButton('header-cart', true);
511
607
  ```
512
608
 
513
- #### Live Cart Display
609
+ **Parameters:**
610
+ - `containerId` - Where to place the button
611
+ - `showItemsCount` - Show item count badge (optional)
514
612
 
515
- **`ui.cartTotal(elementId: string): void`**
613
+ **Use case:** Header navigation, sidebar
516
614
 
517
- Bind an element to display the live cart total (automatically updates when cart changes):
615
+ #### Floating Cart Button
518
616
 
519
617
  ```js
520
- client.ui.cartTotal('cart-total-display');
618
+ client.ui.floatingCartButton(true);
521
619
  ```
522
620
 
523
- **`ui.cartItemsCount(elementId: string): void`**
621
+ **Parameters:**
622
+ - `showItemsCount` - Show item count badge (optional)
623
+
624
+ **Use case:** Always-visible cart access (bottom-right corner)
524
625
 
525
- Bind an element to display the live cart items count (automatically updates when cart changes):
626
+ #### Live Cart Data Display
627
+
628
+ Bind elements to auto-update with cart data:
526
629
 
527
630
  ```js
528
- client.ui.cartItemsCount('cart-items-badge');
631
+ // Show live subtotal
632
+ client.ui.cartSubtotal('cart-total-display');
633
+
634
+ // Show live item count
635
+ client.ui.cartItemsCount('cart-badge');
636
+ ```
637
+
638
+ **Example:**
639
+ ```html
640
+ <nav>
641
+ <span>Cart: $<span id="cart-total-display">0.00</span></span>
642
+ <span>(<span id="cart-badge">0</span> items)</span>
643
+ </nav>
529
644
  ```
530
645
 
531
646
  ### Builder Methods (Development Mode)
@@ -815,359 +930,1295 @@ window.elements.onAllActions((data, metadata) => {
815
930
 
816
931
  See [`docs/EVENTS.md`](docs/EVENTS.md) for complete event reference with implementation examples.
817
932
 
818
- ## ⚙️ Configuration
819
-
820
- Configure the SDK when initializing:
821
-
822
- ```js
823
- const client = await Elements('YOUR_API_KEY', {
824
- env: 'production', // 'local' | 'development' | 'staging' | 'production'
825
- enableDebugging: false, // Enable console logging (development only)
826
- isBuilder: false, // Enable builder methods (development only)
827
- customTheme: { /* theme overrides */ },
828
- proxy: { /* proxy configuration */ }
829
- });
830
- ```
831
-
832
- ### Environment Options
833
-
834
- - **`production`**: Live environment for customer-facing sites
835
- - **`staging`**: Pre-production testing environment
836
- - **`development`**: Development environment with additional debugging
837
- - **`local`**: Local development environment
838
-
839
- ### Auto-init Data Attributes
840
-
841
- When using auto-initialization, configure via data attributes:
842
-
843
- - `data-liquid-commerce-elements`: Required flag to enable auto-init
844
- - `data-token`: Your API key (required)
845
- - `data-env`: Environment (defaults to production)
846
- - `data-cart-id`: Container ID for cart button
847
- - `data-enable-debugging`: Enable debugging mode
848
- - `data-container-X` / `data-product-X`: Product mapping pairs
849
-
850
933
  ## 🎨 Themes & Customization
851
934
 
852
- Customize the appearance of SDK components using the theme system:
935
+ The SDK provides a theming system that lets you match components to your brand.
936
+
937
+ ### Global Theming
853
938
 
854
939
  ```js
855
940
  const client = await Elements('YOUR_API_KEY', {
856
- env: 'production',
857
941
  customTheme: {
858
942
  global: {
859
- colors: {
860
- primary: '#007bff',
861
- secondary: '#6c757d'
862
- },
863
- typography: {
864
- fontFamily: 'Roboto, sans-serif',
865
- fontSize: '16px'
866
- }
867
- },
868
- product: {
869
- layout: {
870
- imagePosition: 'left',
871
- showDescription: true
943
+ theme: {
944
+ primaryColor: '#007bff',
945
+ accentColor: '#6c757d',
946
+ successColor: '#28a745',
947
+ errorColor: '#dc3545',
948
+ warningColor: '#ffc107',
949
+ defaultTextColor: '#212529',
950
+ selectedTextColor: '#ffffff',
951
+ drawerBackgroundColor: '#ffffff',
952
+ buttonCornerRadius: '8px',
953
+ cardCornerRadius: '12px',
954
+ headingFont: {
955
+ name: 'Inter',
956
+ weights: [600, 700]
957
+ },
958
+ paragraphFont: {
959
+ name: 'Inter',
960
+ weights: [400, 500]
961
+ }
872
962
  },
873
- colors: {
874
- price: '#28a745',
875
- sale: '#dc3545'
876
- }
877
- },
878
- cart: {
879
- layout: {
880
- showRetailerLogos: true,
881
- compactMode: false
882
- }
883
- },
884
- checkout: {
885
963
  layout: {
886
- singlePage: true,
887
- showOrderSummary: true
964
+ enablePersonalization: true,
965
+ personalizationText: 'Customize your product',
966
+ personalizationCardStyle: 'outlined',
967
+ allowPromoCodes: true,
968
+ inputFieldStyle: 'outlined',
969
+ poweredByMode: 'light'
888
970
  }
889
971
  }
890
972
  }
891
973
  });
892
974
  ```
893
975
 
894
- In builder mode, themes can be updated dynamically:
976
+ ### Component-Specific Theming
977
+
978
+ #### Product Component
895
979
 
896
980
  ```js
897
- // Update themes in real-time (builder mode only)
898
- await client.builder.updateComponentGlobalConfigs({
899
- colors: { primary: '#ff6b6b' }
981
+ customTheme: {
982
+ product: {
983
+ theme: {
984
+ backgroundColor: '#ffffff'
985
+ },
986
+ layout: {
987
+ showImages: true,
988
+ showTitle: true,
989
+ showDescription: true,
990
+ showQuantityCounter: true,
991
+ quantityCounterStyle: 'outlined',
992
+ fulfillmentDisplay: 'carousel',
993
+ enableShippingFulfillment: true,
994
+ enableOnDemandFulfillment: true,
995
+ addToCartButtonText: 'Add to Cart',
996
+ buyNowButtonText: 'Buy Now'
997
+ }
998
+ }
999
+ }
1000
+ ```
1001
+
1002
+ #### Cart Component
1003
+
1004
+ ```js
1005
+ customTheme: {
1006
+ cart: {
1007
+ theme: {
1008
+ backgroundColor: '#ffffff'
1009
+ },
1010
+ layout: {
1011
+ showQuantityCounter: true,
1012
+ quantityCounterStyle: 'outlined',
1013
+ drawerHeaderText: 'Your Cart',
1014
+ goToCheckoutButtonText: 'Checkout'
1015
+ }
1016
+ }
1017
+ }
1018
+ ```
1019
+
1020
+ #### Checkout Component
1021
+
1022
+ ```js
1023
+ customTheme: {
1024
+ checkout: {
1025
+ theme: {
1026
+ backgroundColor: '#ffffff',
1027
+ checkoutCompleted: {
1028
+ customLogo: 'https://yourdomain.com/logo.png',
1029
+ customText: 'Thank you for your order!'
1030
+ }
1031
+ },
1032
+ layout: {
1033
+ emailOptIn: {
1034
+ show: true,
1035
+ checked: false,
1036
+ text: 'Email me with news'
1037
+ },
1038
+ smsOptIn: {
1039
+ show: true,
1040
+ checked: false,
1041
+ text: 'Text me updates'
1042
+ },
1043
+ allowGiftCards: true,
1044
+ drawerHeaderText: 'Checkout',
1045
+ placeOrderButtonText: 'Place Order'
1046
+ }
1047
+ }
1048
+ }
1049
+ ```
1050
+
1051
+ #### Address Component
1052
+
1053
+ ```js
1054
+ customTheme: {
1055
+ address: {
1056
+ theme: {
1057
+ backgroundColor: '#ffffff'
1058
+ }
1059
+ }
1060
+ }
1061
+ ```
1062
+
1063
+ ### Dynamic Theme Updates (Builder Mode)
1064
+
1065
+ In development with `isBuilder: true`, update themes in real-time:
1066
+
1067
+ ```js
1068
+ const client = await Elements('YOUR_API_KEY', {
1069
+ env: 'development',
1070
+ isBuilder: true
900
1071
  });
901
1072
 
1073
+ // Update global theme
1074
+ await client.builder.updateComponentGlobalConfigs({
1075
+ theme: { primaryColor: '#ff6b6b' }
1076
+ });
1077
+
1078
+ // Update component-specific themes
902
1079
  await client.builder.updateProductComponent({
903
- layout: { imagePosition: 'right' }
1080
+ layout: { addToCartButtonText: 'Add to Bag' }
1081
+ });
1082
+
1083
+ client.builder.updateCartComponent({
1084
+ layout: { drawerHeaderText: 'Shopping Bag' }
1085
+ });
1086
+
1087
+ client.builder.updateCheckoutComponent({
1088
+ layout: { placeOrderButtonText: 'Complete Purchase' }
1089
+ });
1090
+
1091
+ client.builder.updateAddressComponent({
1092
+ theme: { backgroundColor: '#f8f9fa' }
904
1093
  });
905
1094
  ```
906
1095
 
907
- ## 🔒 Proxy Configuration
1096
+ **📖 For complete theming documentation:** See [`docs/THEMING.md`](docs/THEMING.md)
908
1097
 
909
- Route API requests through your server to avoid ad blockers:
1098
+ ---
1099
+
1100
+ ## 🎁 Features Deep Dive
1101
+
1102
+ ### Product Personalization (Engraving)
1103
+
1104
+ The SDK provides a comprehensive personalization/engraving feature for products that support it. The personalization experience varies based on context:
1105
+
1106
+ #### Product View
1107
+ When browsing products, customers can add personalization through an enhanced form that includes:
1108
+ - Product information with pricing
1109
+ - Fulfillment/retailer selection (with pricing comparison)
1110
+ - Multi-line engraving inputs with character limits
1111
+ - Real-time price updates as customers select different retailers
1112
+ - Add-to-cart with personalization in one step
1113
+
1114
+ ```js
1115
+ // Personalization appears automatically for engravable products
1116
+ // Customers can add engraving text and select which retailer to fulfill from
1117
+
1118
+ // Listen for when personalization is added via add-to-cart
1119
+ window.addEventListener('lce:actions.product_add_to_cart', (event) => {
1120
+ const { hasEngraving, engravingLines } = event.detail.data;
1121
+ if (hasEngraving) {
1122
+ console.log('Customer personalized:', engravingLines);
1123
+ }
1124
+ });
1125
+ ```
1126
+
1127
+ #### Cart View
1128
+ In the cart, personalized items display:
1129
+ - Personalization text lines
1130
+ - Engraving fee (per item and total for quantity)
1131
+ - **Edit** button to modify the personalization
1132
+ - **Remove** button to remove personalization
1133
+
1134
+ ```js
1135
+ // Customers can edit or remove engraving from cart items
1136
+ window.addEventListener('lce:actions.cart_item_engraving_updated', (event) => {
1137
+ const { identifier, engravingLines } = event.detail.data;
1138
+ console.log('Cart item engraving updated:', engravingLines);
1139
+ });
1140
+ ```
1141
+
1142
+ #### Checkout View
1143
+ During checkout, personalized items show:
1144
+ - Personalization text lines (read-only)
1145
+ - Engraving fee included in pricing
1146
+ - **Remove** button only (editing not allowed in checkout)
1147
+
1148
+ **Design Decision:** Editing personalization during checkout is intentionally disabled to prevent order processing complications. Customers must return to the cart to make changes.
1149
+
1150
+ #### Theming & Configuration
1151
+
1152
+ Control personalization display through global configuration:
1153
+
1154
+ ```js
1155
+ customTheme: {
1156
+ global: {
1157
+ layout: {
1158
+ enablePersonalization: true,
1159
+ personalizationText: 'Personalize your product',
1160
+ personalizationCardStyle: 'outlined' // or 'filled'
1161
+ }
1162
+ }
1163
+ }
1164
+ ```
1165
+
1166
+ #### Key Features
1167
+ - **Smart pricing:** Automatically includes engraving fees in product price
1168
+ - **Retailer selection:** Compare prices from different retailers during personalization
1169
+ - **Character limits:** Enforces maximum characters per line
1170
+ - **Uppercase conversion:** Engraving text is automatically converted to uppercase
1171
+ - **Multi-line support:** Products can support 1 or more engraving lines
1172
+ - **Fee transparency:** Shows per-item and total fees (e.g., "$5.00 ($2.50 ea)")
1173
+
1174
+ **Note:** Personalization is automatically enabled for products that support it. The SDK handles all UI, validation, and state management.
1175
+
1176
+ ### Gift Options
1177
+
1178
+ Allow orders to be marked as gifts with custom messages:
1179
+
1180
+ ```js
1181
+ // Enable via theme
1182
+ customTheme: {
1183
+ checkout: {
1184
+ layout: {
1185
+ allowGiftOptions: true
1186
+ }
1187
+ }
1188
+ }
1189
+
1190
+ // Toggle gift mode programmatically
1191
+ await client.actions.checkout.toggleIsGift(true);
1192
+
1193
+ // Set gift message
1194
+ await client.actions.checkout.updateGiftInfo({
1195
+ recipientName: 'John Doe',
1196
+ message: 'Happy Birthday!'
1197
+ });
1198
+
1199
+ // Listen for gift toggles
1200
+ window.addEventListener('lce:actions.checkout_is_gift_toggled', (event) => {
1201
+ const { isGift } = event.detail.data;
1202
+ console.log('Order is gift:', isGift);
1203
+ });
1204
+ ```
1205
+
1206
+ ### Tips (On-Demand Delivery)
1207
+
1208
+ Allow customers to tip delivery drivers:
1209
+
1210
+ ```js
1211
+ // Tips are automatically enabled for onDemand fulfillment types
1212
+
1213
+ // Listen for tip updates
1214
+ window.addEventListener('lce:actions.checkout_tip_updated', (event) => {
1215
+ const { tipAmount, total } = event.detail.data;
1216
+ console.log(`Customer tipped $${tipAmount}`);
1217
+ });
1218
+ ```
1219
+
1220
+ Tips are calculated as a percentage or fixed amount and added to the order total.
1221
+
1222
+ ### Gift Cards
1223
+
1224
+ Accept gift card payments at checkout:
1225
+
1226
+ ```js
1227
+ // Enable via theme
1228
+ customTheme: {
1229
+ checkout: {
1230
+ layout: {
1231
+ allowGiftCards: true
1232
+ }
1233
+ }
1234
+ }
1235
+
1236
+ // Apply gift card programmatically
1237
+ await client.actions.checkout.applyGiftCard('GIFT-1234-5678-9012');
1238
+
1239
+ // Remove gift card
1240
+ await client.actions.checkout.removeGiftCard('GIFT-1234-5678-9012');
1241
+
1242
+ // Listen for gift card events
1243
+ window.addEventListener('lce:actions.checkout_gift_card_applied', (event) => {
1244
+ const { code, appliedAmount, remainingBalance } = event.detail.data;
1245
+ console.log(`Applied $${appliedAmount}, Remaining: $${remainingBalance}`);
1246
+ });
1247
+
1248
+ window.addEventListener('lce:actions.checkout_gift_card_failed', (event) => {
1249
+ const { code, error } = event.detail.data;
1250
+ console.log('Gift card failed:', error);
1251
+ });
1252
+ ```
1253
+
1254
+ ### Promo Codes
1255
+
1256
+ Apply promotional discount codes:
910
1257
 
911
1258
  ```js
1259
+ // Apply to cart
1260
+ await client.actions.cart.applyPromoCode('SUMMER20');
1261
+
1262
+ // Apply to checkout
1263
+ await client.actions.checkout.applyPromoCode('SAVE10');
1264
+
1265
+ // Remove promo code
1266
+ await client.actions.cart.removePromoCode();
1267
+
1268
+ // Listen for promo events
1269
+ window.addEventListener('lce:actions.cart_promo_code_applied', (event) => {
1270
+ const { code, discountAmount, newTotal } = event.detail.data;
1271
+ console.log(`${code} saved $${discountAmount}! New total: $${newTotal}`);
1272
+ });
1273
+
1274
+ window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
1275
+ const { code, error } = event.detail.data;
1276
+ console.log('Promo failed:', error.message);
1277
+ });
1278
+ ```
1279
+
1280
+ ### Promo Ticker
1281
+
1282
+ Display rotating promotional messages at the top of your site:
1283
+
1284
+ ```js
1285
+ // Via initialization config
912
1286
  const client = await Elements('YOUR_API_KEY', {
913
- env: 'production',
914
- proxy: {
915
- baseUrl: 'https://yourdomain.com/api/liquidcommerce',
916
- headers: {
917
- 'X-Custom-Header': 'value'
1287
+ promoTicker: [
1288
+ {
1289
+ promoCode: 'FREESHIP',
1290
+ text: ['Free Shipping Today!', 'Use code FREESHIP'],
1291
+ separator: '',
1292
+ activeFrom: '2025-01-01T00:00:00Z',
1293
+ activeUntil: '2025-12-31T23:59:59Z'
1294
+ },
1295
+ {
1296
+ promoCode: 'SAVE20',
1297
+ text: ['20% Off Sitewide', 'Limited Time Only'],
1298
+ separator: '|',
1299
+ activeFrom: '2025-06-01T00:00:00Z',
1300
+ activeUntil: '2025-06-30T23:59:59Z'
1301
+ }
1302
+ ]
1303
+ });
1304
+
1305
+ // Via auto-init
1306
+ <script
1307
+ data-liquid-commerce-elements
1308
+ data-token="YOUR_API_KEY"
1309
+ data-promo-code="FREESHIP"
1310
+ data-promo-text="Free Shipping Today!|Use code FREESHIP"
1311
+ data-promo-separator="•"
1312
+ data-promo-active-from="2025-01-01T00:00:00Z"
1313
+ data-promo-active-until="2025-12-31T23:59:59Z"
1314
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
1315
+ ></script>
1316
+ ```
1317
+
1318
+ The ticker automatically rotates messages and only shows active promotions.
1319
+
1320
+ ### Marketing Preferences
1321
+
1322
+ Allow customers to opt-in to email and SMS marketing:
1323
+
1324
+ ```js
1325
+ // Set defaults via theme
1326
+ customTheme: {
1327
+ checkout: {
1328
+ layout: {
1329
+ emailOptIn: { checked: false, visible: true },
1330
+ smsOptIn: { checked: false, visible: true }
918
1331
  }
919
1332
  }
1333
+ }
1334
+
1335
+ // Update preferences programmatically
1336
+ await client.actions.checkout.toggleMarketingPreferences('canEmail', true);
1337
+ await client.actions.checkout.toggleMarketingPreferences('canSms', true);
1338
+
1339
+ // Listen for preference changes
1340
+ window.addEventListener('lce:actions.checkout_marketing_preferences_toggled', (event) => {
1341
+ const { field, value } = event.detail.data;
1342
+ console.log(`Customer ${value ? 'opted-in' : 'opted-out'} of ${field}`);
920
1343
  });
921
1344
  ```
922
1345
 
923
- The SDK automatically handles routing and required headers. See [`docs/PROXY.md`](docs/PROXY.md) for complete proxy setup guide with Next.js examples.
1346
+ ### Purchase Minimum Alerts
924
1347
 
925
- ## 📚 Documentation
1348
+ Automatically displays alerts when a retailer has minimum purchase requirements. No configuration needed - the SDK handles this automatically based on retailer rules.
926
1349
 
927
- For detailed guides and advanced usage:
1350
+ ### Age Verification
928
1351
 
929
- - [`docs/ACTIONS.md`](docs/ACTIONS.md) - Complete actions reference with business use cases
930
- - [`docs/EVENTS.md`](docs/EVENTS.md) - Events guide with implementation examples
931
- - [`docs/BROWSER_SUPPORT.md`](docs/BROWSER_SUPPORT.md) - Detailed browser compatibility
932
- - [`docs/PROXY.md`](docs/PROXY.md) - Proxy configuration for ad blocker avoidance
1352
+ For age-restricted products (alcohol, tobacco, etc.), the SDK automatically displays age verification prompts during checkout. This is handled based on product metadata and cannot be disabled for restricted items.
933
1353
 
934
- ## 🏷️ Versioning
1354
+ ### Pre-Sale Countdown
1355
+
1356
+ For pre-sale or upcoming products, the SDK automatically displays a countdown timer until the product becomes available. Customers can add pre-sale items to cart, and the SDK handles the special fulfillment flow.
1357
+
1358
+ ```js
1359
+ // Listen for when product is added to cart
1360
+ window.addEventListener('lce:actions.product_add_to_cart', (event) => {
1361
+ const { productId } = event.detail.data;
1362
+ console.log(`Product ${productId} added to cart`);
1363
+ });
1364
+ ```
1365
+
1366
+ ---
935
1367
 
936
- This project uses Semantic Versioning. The SDK is available in two environments:
1368
+ ## 🔧 Core Capabilities
937
1369
 
938
- ### Beta Environment
939
- - Branch: `beta`
940
- - Base URL: `https://assets-elements.liquidcommerce.us/all/beta/`
941
- - Purpose: Testing and pre-release features
1370
+ The SDK includes several built-in services that work behind the scenes to provide a robust, production-ready experience.
942
1371
 
943
- ### Production Environment
944
- - Branch: `main`
945
- - Base URL: `https://assets-elements.liquidcommerce.us/all/`
946
- - Purpose: Stable releases for production use
1372
+ ### State Management
1373
+
1374
+ The SDK uses a centralized store for all state management. Access state data via actions:
1375
+
1376
+ ```js
1377
+ // Get current cart state
1378
+ const cart = await client.actions.cart.getDetails();
1379
+ console.log(cart.items, cart.subtotal, cart.itemCount);
947
1380
 
948
- ### CDN Path Structure
1381
+ // Get current checkout state
1382
+ const checkout = await client.actions.checkout.getDetails();
1383
+ console.log(checkout.total, checkout.customerInfo, checkout.isGift);
949
1384
 
1385
+ // Get current address
1386
+ const address = await client.actions.address.getDetails();
1387
+ console.log(address.formattedAddress, address.coordinates);
1388
+
1389
+ // Get product details
1390
+ const product = await client.actions.product.getDetails('00619947000020');
1391
+ console.log(product.name, product.price, product.variants);
950
1392
  ```
951
- elements-sdk/
952
- └── all/
953
- ├── beta/
954
- │ ├── 1.2.3/elements.js
955
- │ ├── 1.2.4/elements.js
956
- │ └── elements.js (beta latest)
957
- ├── 1.2.2/elements.js (production)
958
- ├── 1.2.3/elements.js (production)
959
- └── elements.js (production latest)
1393
+
1394
+ **State is persistent:** Cart and address data persist across page reloads using localStorage.
1395
+
1396
+ ### Event System (PubSub)
1397
+
1398
+ All SDK interactions emit events through a centralized event system:
1399
+
1400
+ ```js
1401
+ // Subscribe to specific event
1402
+ window.addEventListener('lce:actions.cart_updated', (event) => {
1403
+ const cartData = event.detail.data;
1404
+ console.log('Cart changed:', cartData);
1405
+ });
1406
+
1407
+ // Subscribe to all action events
1408
+ if (window.elements) {
1409
+ window.elements.onAllActions((data, metadata) => {
1410
+ console.log('Action:', metadata.eventName, data);
1411
+ });
1412
+ }
1413
+
1414
+ // Subscribe to all form events
1415
+ if (window.elements) {
1416
+ window.elements.onAllForms((data, metadata) => {
1417
+ console.log('Form:', metadata.eventName, data);
1418
+ });
1419
+ }
1420
+ ```
1421
+
1422
+ **Event format:**
1423
+ ```js
1424
+ {
1425
+ detail: {
1426
+ data: { /* event-specific payload */ },
1427
+ metadata: {
1428
+ eventName: 'lce:actions.cart_updated',
1429
+ timestamp: 1699564800000,
1430
+ source: 'sdk'
1431
+ }
1432
+ }
1433
+ }
1434
+ ```
1435
+
1436
+ ### Telemetry & Analytics
1437
+
1438
+ The SDK automatically tracks user interactions and performance metrics:
1439
+
1440
+ - **User interactions:** Add to cart, checkout started, checkout completed
1441
+ - **Performance metrics:** Component load times, API response times
1442
+ - **Error tracking:** Failed API calls, validation errors
1443
+
1444
+ **Note:** The SDK includes automatic Google Tag Manager (GTM) integration that tracks e-commerce events. GTM configuration is managed through your LiquidCommerce dashboard, not the client initialization.
1445
+
1446
+ **Custom Analytics:**
1447
+
1448
+ ```js
1449
+ // Listen to events for custom analytics tracking
1450
+ window.addEventListener('lce:actions.product_add_to_cart', (event) => {
1451
+ const { productId, price, quantity } = event.detail.data;
1452
+
1453
+ // Track with your analytics provider
1454
+ gtag('event', 'add_to_cart', {
1455
+ currency: 'USD',
1456
+ value: price * quantity,
1457
+ items: [{ item_id: productId, quantity }]
1458
+ });
1459
+
1460
+ // Or Segment
1461
+ analytics.track('Product Added', {
1462
+ product_id: productId,
1463
+ price,
1464
+ quantity
1465
+ });
1466
+ });
960
1467
  ```
961
1468
 
962
- ## 🎭 Demo Pages
1469
+ ### Circuit Breaker
963
1470
 
964
- The SDK includes ready-to-use demo pages in the `demo/` folder that showcase different implementation approaches:
1471
+ The SDK includes a circuit breaker pattern to prevent cascading failures:
965
1472
 
966
- ### Simple Demo (`demo/simple.html`)
1473
+ ```js
1474
+ // Automatically handles API failures
1475
+ // - After 5 consecutive failures, circuit opens
1476
+ // - Requests fail fast without hitting the API
1477
+ // - After 30 seconds, circuit half-opens
1478
+ // - Next successful request closes the circuit
1479
+ ```
1480
+
1481
+ **Circuit states:**
1482
+ - **Closed:** Normal operation, all requests go through
1483
+ - **Open:** API is failing, requests fail fast
1484
+ - **Half-Open:** Testing if API recovered, limited requests allowed
1485
+
1486
+ This protects your site from slowdowns when the API is experiencing issues.
1487
+
1488
+ ### Fingerprinting
1489
+
1490
+ The SDK generates a unique device fingerprint for fraud prevention and analytics:
1491
+
1492
+ ```js
1493
+ // Automatically tracked:
1494
+ // - Browser fingerprint
1495
+ // - Device characteristics
1496
+ // - Session information
1497
+
1498
+ // Used for:
1499
+ // - Fraud detection
1500
+ // - Cart persistence across devices
1501
+ // - Personalization
1502
+ ```
1503
+
1504
+ Fingerprinting is handled automatically and requires no configuration.
1505
+
1506
+ ### Authentication
1507
+
1508
+ The SDK handles authentication automatically using your API key:
1509
+
1510
+ ```js
1511
+ const client = await Elements('YOUR_API_KEY', {
1512
+ env: 'production'
1513
+ });
1514
+
1515
+ // All API requests include:
1516
+ // - API key authentication
1517
+ // - CORS headers
1518
+ // - Request signing (when required)
1519
+ ```
1520
+
1521
+ **Token refresh:** The SDK automatically handles token expiration and refresh.
1522
+
1523
+ ### Logger
967
1524
 
968
- Demonstrates **auto-initialization** using data attributes - the easiest way to get started:
1525
+ Built-in logging system with configurable levels:
1526
+
1527
+ ```js
1528
+ const client = await Elements('YOUR_API_KEY', {
1529
+ debugMode: 'console' // 'none' | 'console' | 'panel'
1530
+ });
1531
+
1532
+ // Debug mode options:
1533
+ // - 'none': No logging (production default)
1534
+ // - 'console': Logs to browser console
1535
+ // - 'panel': Shows visual debug panel + console logs
1536
+ ```
1537
+
1538
+ **Console debug output:**
1539
+ ```
1540
+ [LCE SDK] Product loaded: product-123
1541
+ [LCE SDK] Cart updated: 3 items, $45.99
1542
+ [LCE SDK] Checkout started
1543
+ [LCE SDK] API call: POST /cart/add (152ms)
1544
+ ```
1545
+
1546
+ **Debug panel:**
1547
+ - Real-time event stream
1548
+ - API call inspector
1549
+ - State viewer
1550
+ - Performance metrics
1551
+
1552
+ ### Command Pattern
1553
+
1554
+ The SDK uses a command pattern for all operations:
1555
+
1556
+ ```js
1557
+ // Commands are:
1558
+ // - Queued for execution
1559
+ // - Retried on failure
1560
+ // - Logged for debugging
1561
+ // - Cancelable
1562
+
1563
+ // Example: Adding to cart
1564
+ // 1. Command created: AddToCartCommand
1565
+ // 2. Command queued
1566
+ // 3. Command executed
1567
+ // 4. Success event emitted
1568
+ // 5. UI updated
1569
+
1570
+ // This ensures:
1571
+ // - Consistent error handling
1572
+ // - Automatic retries
1573
+ // - Full audit trail
1574
+ ```
1575
+
1576
+ ### Component Factory
1577
+
1578
+ Components are created on-demand using a factory pattern:
1579
+
1580
+ ```js
1581
+ // When you call:
1582
+ await client.injectProductElement([
1583
+ { containerId: 'pdp-1', identifier: 'product-123' }
1584
+ ]);
1585
+
1586
+ // The SDK:
1587
+ // 1. Creates a ProductComponent instance
1588
+ // 2. Registers it with the factory
1589
+ // 3. Injects it into the DOM
1590
+ // 4. Attaches event listeners
1591
+ // 5. Loads product data
1592
+ // 6. Renders the component
1593
+
1594
+ // Components are:
1595
+ // - Lazily loaded
1596
+ // - Automatically cleaned up
1597
+ // - Reusable across pages
1598
+ ```
1599
+
1600
+ ### Singleton Manager
1601
+
1602
+ Core services are managed as singletons:
1603
+
1604
+ ```js
1605
+ // These services are initialized once and reused:
1606
+ // - ApiClient
1607
+ // - Store
1608
+ // - PubSub
1609
+ // - Logger
1610
+ // - Telemetry
1611
+ // - CircuitBreaker
1612
+ // - Fingerprint
1613
+ // - Auth
1614
+
1615
+ // This ensures:
1616
+ // - Consistent state
1617
+ // - Efficient memory usage
1618
+ // - No duplicate API calls
1619
+ ```
1620
+
1621
+ ---
1622
+
1623
+ ## 🏗️ Integration Patterns
1624
+
1625
+ ### React Integration
1626
+
1627
+ ```jsx
1628
+ import { useEffect, useState } from 'react';
1629
+ import { Elements } from '@liquidcommerce/elements-sdk';
1630
+
1631
+ function ProductPage({ productId }) {
1632
+ const [client, setClient] = useState(null);
1633
+
1634
+ useEffect(() => {
1635
+ async function initSDK() {
1636
+ const elementsClient = await Elements(process.env.REACT_APP_LCE_API_KEY, {
1637
+ env: 'production'
1638
+ });
1639
+ setClient(elementsClient);
1640
+
1641
+ // Inject product
1642
+ await elementsClient.injectProductElement([
1643
+ { containerId: 'product-container', identifier: productId }
1644
+ ]);
1645
+
1646
+ // Create cart button
1647
+ elementsClient.ui.cartButton('cart-button', true);
1648
+ }
1649
+
1650
+ initSDK();
1651
+
1652
+ // Cleanup
1653
+ return () => {
1654
+ // SDK handles cleanup automatically
1655
+ };
1656
+ }, [productId]);
1657
+
1658
+ return (
1659
+ <div>
1660
+ <div id="cart-button"></div>
1661
+ <div id="product-container"></div>
1662
+ </div>
1663
+ );
1664
+ }
1665
+ ```
1666
+
1667
+ ### Vue Integration
1668
+
1669
+ ```vue
1670
+ <template>
1671
+ <div>
1672
+ <div ref="cartButton"></div>
1673
+ <div ref="productContainer"></div>
1674
+ </div>
1675
+ </template>
1676
+
1677
+ <script>
1678
+ import { Elements } from '@liquidcommerce/elements-sdk';
1679
+
1680
+ export default {
1681
+ name: 'ProductPage',
1682
+ props: ['productId'],
1683
+ async mounted() {
1684
+ this.client = await Elements(process.env.VUE_APP_LCE_API_KEY, {
1685
+ env: 'production'
1686
+ });
1687
+
1688
+ await this.client.injectProductElement([
1689
+ { containerId: this.$refs.productContainer.id, identifier: this.productId }
1690
+ ]);
1691
+
1692
+ this.client.ui.cartButton(this.$refs.cartButton.id, true);
1693
+ }
1694
+ }
1695
+ </script>
1696
+ ```
1697
+
1698
+ ### Next.js Integration
1699
+
1700
+ ```tsx
1701
+ 'use client';
1702
+
1703
+ import { useEffect } from 'react';
1704
+
1705
+ export default function ProductPage({ productId }: { productId: string }) {
1706
+ useEffect(() => {
1707
+ // Load SDK script
1708
+ const script = document.createElement('script');
1709
+ script.src = 'https://assets-elements.liquidcommerce.us/all/elements.js';
1710
+ script.async = true;
1711
+ script.onload = async () => {
1712
+ const client = await (window as any).Elements(process.env.NEXT_PUBLIC_LCE_API_KEY, {
1713
+ env: 'production'
1714
+ });
1715
+
1716
+ await client.injectProductElement([
1717
+ { containerId: 'product-container', identifier: productId }
1718
+ ]);
1719
+
1720
+ client.ui.floatingCartButton(true);
1721
+ };
1722
+ document.body.appendChild(script);
1723
+
1724
+ return () => {
1725
+ document.body.removeChild(script);
1726
+ };
1727
+ }, [productId]);
1728
+
1729
+ return <div id="product-container"></div>;
1730
+ }
1731
+ ```
1732
+
1733
+ ### WordPress Integration
969
1734
 
970
1735
  ```html
971
- <!-- Auto-init with data attributes -->
1736
+ <!-- In your theme's header.php or functions.php -->
972
1737
  <script
973
1738
  data-liquid-commerce-elements
974
- data-token="YOUR_API_KEY"
975
- data-env="development"
976
- data-enable-debugging
977
- src="../umd/elements.js"
1739
+ data-token="<?php echo get_option('lce_api_key'); ?>"
1740
+ data-env="production"
1741
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
978
1742
  ></script>
1743
+
1744
+ <!-- In your product template -->
1745
+ <div data-lce-product="<?php echo get_post_meta(get_the_ID(), 'product_upc', true); ?>"></div>
979
1746
  ```
980
1747
 
981
- **Features shown:**
982
- - Auto-initialization with data attributes
983
- - Multiple product mapping methods (data attributes, JSON script, annotated elements)
984
- - Event listening for actions and forms
985
- - Basic container setup for products, cart, and checkout
1748
+ ### Shopify Integration
1749
+
1750
+ ```html
1751
+ <!-- In theme.liquid -->
1752
+ <script
1753
+ data-liquid-commerce-elements
1754
+ data-token="{{ settings.lce_api_key }}"
1755
+ data-env="production"
1756
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
1757
+ ></script>
986
1758
 
987
- **Best for:** Quick prototyping, simple integrations, getting familiar with the SDK
1759
+ <!-- In product template -->
1760
+ <div data-lce-product="{{ product.barcode }}"></div>
1761
+ ```
988
1762
 
989
- ### Advanced Demo (`demo/advanced.html`)
1763
+ ### Multi-Page Applications
990
1764
 
991
- Demonstrates **programmatic initialization** for full control:
1765
+ For SPAs and multi-page apps, initialize once and reuse:
992
1766
 
993
- ```javascript
994
- const client = await window.Elements(API_KEY, {
995
- env: "development",
996
- enableDebugging: true,
997
- customTheme: { /* theme config */ }
998
- });
1767
+ ```js
1768
+ // app.js (initialize once)
1769
+ let elementsClient = null;
1770
+
1771
+ async function getElementsClient() {
1772
+ if (!elementsClient) {
1773
+ elementsClient = await Elements('YOUR_API_KEY', {
1774
+ env: 'production'
1775
+ });
1776
+ }
1777
+ return elementsClient;
1778
+ }
999
1779
 
1000
- // Programmatic component injection
1001
- client.buttons.openCart("buttons-container");
1780
+ // product-page.js
1781
+ const client = await getElementsClient();
1002
1782
  await client.injectProductElement([
1003
- { containerId: "pdp-container", identifier: '00619947000020' }
1783
+ { containerId: 'pdp-1', identifier: productId }
1004
1784
  ]);
1005
- await client.injectCheckoutElement("checkout-container");
1785
+
1786
+ // cart-page.js
1787
+ const client = await getElementsClient();
1788
+ await client.injectCartElement('cart-container');
1006
1789
  ```
1007
1790
 
1008
- **Features shown:**
1009
- - Manual client initialization with full configuration
1010
- - Programmatic component injection
1011
- - Builder methods for theme updates (commented examples)
1012
- - Advanced event handling
1013
- - Dynamic theme updates
1791
+ ---
1792
+
1793
+ ## 🚨 Error Handling
1794
+
1795
+ ### Initialization Errors
1014
1796
 
1015
- **Best for:** Complex integrations, custom workflows, theme customization, production implementations
1797
+ ```js
1798
+ try {
1799
+ const client = await Elements('YOUR_API_KEY', {
1800
+ env: 'production'
1801
+ });
1802
+ } catch (error) {
1803
+ if (error.message.includes('Invalid API key')) {
1804
+ console.error('Authentication failed');
1805
+ } else if (error.message.includes('Network')) {
1806
+ console.error('Network error - check connectivity');
1807
+ } else {
1808
+ console.error('SDK initialization failed:', error);
1809
+ }
1810
+ }
1811
+ ```
1016
1812
 
1017
- ### Running the Demos
1813
+ ### Action Errors
1018
1814
 
1019
- 1. **Clone the repository**
1020
- 2. **Open demo files** in your browser
1021
- 3. **Update API keys** with your own credentials
1022
- 4. **Modify environment** settings as needed (`development`, `staging`, `production`)
1815
+ All actions emit failure events with detailed error information:
1023
1816
 
1024
- The demos use local UMD builds (`../umd/elements.js`) but can be easily switched to CDN URLs for testing.
1817
+ ```js
1818
+ // Product loaded successfully
1819
+ window.addEventListener('lce:actions.product_loaded', (event) => {
1820
+ const { identifier, productData } = event.detail.data;
1821
+ console.log(`Product ${identifier} loaded successfully`);
1822
+ });
1025
1823
 
1026
- ## 🛠️ Development Scripts
1824
+ // Cart action failure
1825
+ window.addEventListener('lce:actions.cart_product_add_failed', (event) => {
1826
+ const { identifiers, error } = event.detail.data;
1827
+ console.error('Failed to add products:', error);
1828
+
1829
+ // Show user-friendly message
1830
+ showNotification('Could not add to cart. Please try again.', 'error');
1831
+ });
1027
1832
 
1028
- For SDK development and maintenance, the following npm/pnpm scripts are available:
1833
+ // Checkout failure
1834
+ window.addEventListener('lce:actions.checkout_submit_failed', (event) => {
1835
+ const { error, reason } = event.detail.data;
1836
+ console.error('Checkout failed:', reason);
1837
+
1838
+ // Handle specific errors
1839
+ if (reason.includes('payment')) {
1840
+ showNotification('Payment declined. Please check your card details.', 'error');
1841
+ } else if (reason.includes('inventory')) {
1842
+ showNotification('Some items are no longer available.', 'warning');
1843
+ } else {
1844
+ showNotification('Checkout failed. Please try again.', 'error');
1845
+ }
1846
+ });
1029
1847
 
1030
- ### Build Commands
1848
+ // Address validation failure
1849
+ window.addEventListener('lce:actions.address_failed', (event) => {
1850
+ const { error } = event.detail.data;
1851
+ console.error('Address validation failed:', error);
1852
+ showNotification('Please enter a valid address.', 'error');
1853
+ });
1031
1854
 
1032
- **`build`** - Production build
1033
- ```bash
1034
- pnpm run build
1855
+ // Promo code failure
1856
+ window.addEventListener('lce:actions.cart_promo_code_failed', (event) => {
1857
+ const { code, error } = event.detail.data;
1858
+ console.error(`Promo code ${code} failed:`, error);
1859
+
1860
+ if (error.includes('expired')) {
1861
+ showNotification('This promo code has expired.', 'warning');
1862
+ } else if (error.includes('invalid')) {
1863
+ showNotification('Invalid promo code.', 'error');
1864
+ } else if (error.includes('minimum')) {
1865
+ showNotification('Cart minimum not met for this promo.', 'warning');
1866
+ }
1867
+ });
1035
1868
  ```
1036
- - Creates optimized ESM and UMD bundles for production
1037
- - Generates TypeScript declarations
1038
- - Enables minification and compression
1039
- - Removes console logs and debugging code
1040
- - **Output:** `dist/index.esm.js` (ESM) + `umd/elements.js` (UMD)
1041
1869
 
1042
- **`build:dev`** - Development build
1043
- ```bash
1044
- pnpm run build:dev
1870
+ ### Network Error Recovery
1871
+
1872
+ ```js
1873
+ let retryCount = 0;
1874
+ const maxRetries = 3;
1875
+
1876
+ async function addProductWithRetry(productParams) {
1877
+ try {
1878
+ await client.actions.cart.addProduct(productParams);
1879
+ } catch (error) {
1880
+ if (retryCount < maxRetries && error.message.includes('Network')) {
1881
+ retryCount++;
1882
+ console.log(`Retrying... Attempt ${retryCount}/${maxRetries}`);
1883
+ setTimeout(() => addProductWithRetry(productParams), 1000 * retryCount);
1884
+ } else {
1885
+ console.error('Failed after retries:', error);
1886
+ showNotification('Network error. Please check your connection.', 'error');
1887
+ }
1888
+ }
1889
+ }
1045
1890
  ```
1046
- - Creates unminified bundles with source maps
1047
- - Preserves console logs and debugging code
1048
- - Faster build times for development
1049
- - **Output:** Same as build but with debugging enabled
1050
1891
 
1051
- **`dev`** - Development with watch mode
1052
- ```bash
1053
- pnpm run dev
1892
+ ### Global Error Handler
1893
+
1894
+ ```js
1895
+ // Listen to all failed events
1896
+ window.addEventListener('lce:actions.cart_failed', handleError);
1897
+ window.addEventListener('lce:actions.checkout_failed', handleError);
1898
+ window.addEventListener('lce:actions.address_failed', handleError);
1899
+ window.addEventListener('lce:actions.cart_product_add_failed', handleError);
1900
+
1901
+ function handleError(event) {
1902
+ const { error, context } = event.detail.data;
1903
+
1904
+ // Log to error tracking service
1905
+ if (window.Sentry) {
1906
+ Sentry.captureException(error, {
1907
+ tags: { sdk: 'liquid-commerce' },
1908
+ extra: context
1909
+ });
1910
+ }
1911
+
1912
+ // Show user notification
1913
+ showNotification('Something went wrong. Please try again.', 'error');
1914
+ }
1054
1915
  ```
1055
- - Same as `build:dev` but watches for file changes
1056
- - Automatically rebuilds on source code changes
1057
- - **Best for:** Active development
1058
1916
 
1059
- ### Code Quality Commands
1917
+ ---
1060
1918
 
1061
- **`lint`** - Lint and auto-fix code
1062
- ```bash
1063
- pnpm run lint
1919
+ ## Performance & Best Practices
1920
+
1921
+ ### Lazy Loading Components
1922
+
1923
+ Only inject components when needed:
1924
+
1925
+ ```js
1926
+ // ❌ Don't inject all components upfront
1927
+ await client.injectProductElement([/* 50 products */]);
1928
+ await client.injectCartElement('cart');
1929
+ await client.injectCheckoutElement('checkout');
1930
+
1931
+ // ✅ Inject components as user navigates
1932
+ // On product page:
1933
+ await client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
1934
+
1935
+ // On cart page (when user clicks cart):
1936
+ await client.injectCartElement('cart');
1937
+
1938
+ // On checkout (when user proceeds):
1939
+ await client.injectCheckoutElement('checkout');
1064
1940
  ```
1065
- - Uses Biome to lint TypeScript/JavaScript files
1066
- - Automatically fixes fixable issues
1067
- - Enforces code style and catches common errors
1068
1941
 
1069
- **`format`** - Format code
1070
- ```bash
1071
- pnpm run format
1942
+ ### Reuse Client Instance
1943
+
1944
+ Initialize once, use everywhere:
1945
+
1946
+ ```js
1947
+ // ❌ Don't create multiple clients
1948
+ // page1.js
1949
+ const client1 = await Elements('KEY', { env: 'production' });
1950
+ // page2.js
1951
+ const client2 = await Elements('KEY', { env: 'production' });
1952
+
1953
+ // ✅ Create once, reuse
1954
+ // app.js
1955
+ window.lceClient = await Elements('KEY', { env: 'production' });
1956
+
1957
+ // page1.js
1958
+ const client = window.lceClient;
1959
+ await client.injectProductElement([...]);
1960
+
1961
+ // page2.js
1962
+ const client = window.lceClient;
1963
+ await client.injectCartElement('cart');
1072
1964
  ```
1073
- - Uses Biome to format all source files
1074
- - Ensures consistent code formatting
1075
- - Applies formatting rules defined in `biome.json`
1076
1965
 
1077
- **`check`** - Combined linting and formatting
1078
- ```bash
1079
- pnpm run check
1966
+ ### Batch Product Injections
1967
+
1968
+ Group product injections together:
1969
+
1970
+ ```js
1971
+ // ❌ Don't inject products one by one
1972
+ await client.injectProductElement([{ containerId: 'p1', identifier: 'id1' }]);
1973
+ await client.injectProductElement([{ containerId: 'p2', identifier: 'id2' }]);
1974
+ await client.injectProductElement([{ containerId: 'p3', identifier: 'id3' }]);
1975
+
1976
+ // ✅ Inject all products at once
1977
+ await client.injectProductElement([
1978
+ { containerId: 'p1', identifier: 'id1' },
1979
+ { containerId: 'p2', identifier: 'id2' },
1980
+ { containerId: 'p3', identifier: 'id3' }
1981
+ ]);
1080
1982
  ```
1081
- - Runs both linting and formatting in one command
1082
- - Auto-fixes issues and formats code
1083
- - **Recommended before commits**
1084
1983
 
1085
- **`fl`** - Format, lint, and build (Fast Loop)
1086
- ```bash
1087
- pnpm run fl
1984
+ ### Optimize Event Listeners
1985
+
1986
+ Use event delegation instead of multiple listeners:
1987
+
1988
+ ```js
1989
+ // ❌ Don't listen to every event
1990
+ window.addEventListener('lce:actions.product_loaded', handler);
1991
+ window.addEventListener('lce:actions.product_add_to_cart', handler);
1992
+ window.addEventListener('lce:actions.cart_updated', handler);
1993
+ // ... 20 more listeners
1994
+
1995
+ // ✅ Use consolidated listeners
1996
+ window.elements.onAllActions((data, metadata) => {
1997
+ switch (metadata.eventName) {
1998
+ case 'lce:actions.product_loaded':
1999
+ handleProductLoad(data);
2000
+ break;
2001
+ case 'lce:actions.product_add_to_cart':
2002
+ handleAddToCart(data);
2003
+ break;
2004
+ case 'lce:actions.cart_updated':
2005
+ handleCartUpdate(data);
2006
+ break;
2007
+ }
2008
+ });
1088
2009
  ```
1089
- - Combines `check` + `build:dev`
1090
- - Complete code quality check + development build
1091
- - **Perfect for:** Pre-commit workflow
1092
2010
 
1093
- ### Maintenance Commands
2011
+ ### Defer Non-Critical Operations
1094
2012
 
1095
- **`clean`** - Clean build outputs
1096
- ```bash
1097
- pnpm run clean
2013
+ Load SDK after critical page content:
2014
+
2015
+ ```html
2016
+ <!-- ❌ Don't load SDK in <head> -->
2017
+ <head>
2018
+ <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2019
+ </head>
2020
+
2021
+ <!-- ✅ Load SDK with defer or at end of body -->
2022
+ <head>
2023
+ <script defer src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2024
+ </head>
2025
+
2026
+ <!-- Or -->
2027
+ <body>
2028
+ <!-- Your page content -->
2029
+ <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
2030
+ </body>
1098
2031
  ```
1099
- - Removes `dist/` and `umd/` directories
1100
- - **Use when:** Build artifacts are corrupted
1101
2032
 
1102
- **`clean:hard`** - Complete reset
1103
- ```bash
1104
- pnpm run clean:hard
2033
+ ### Use Auto-Init for Simple Cases
2034
+
2035
+ Auto-init is optimized for performance:
2036
+
2037
+ ```html
2038
+ <!-- ✅ Auto-init is the fastest way for simple setups -->
2039
+ <div data-lce-product="00619947000020"></div>
2040
+ <div data-lce-product="00832889005513"></div>
2041
+
2042
+ <script
2043
+ data-liquid-commerce-elements
2044
+ data-token="YOUR_API_KEY"
2045
+ data-env="production"
2046
+ src="https://assets-elements.liquidcommerce.us/all/elements.js"
2047
+ ></script>
1105
2048
  ```
1106
- - Removes build outputs AND `node_modules/`
1107
- - Reinstalls all dependencies with `pnpm install`
1108
- - Runs a fresh production build
1109
- - **Use when:** Dependency issues or major updates
1110
2049
 
1111
- **`changelog`** - Generate changelog
1112
- ```bash
1113
- pnpm run changelog
2050
+ ### Avoid Unnecessary Re-renders
2051
+
2052
+ Don't repeatedly inject the same component:
2053
+
2054
+ ```js
2055
+ // ❌ Don't re-inject on every state change
2056
+ function updateProduct() {
2057
+ setProductId(newId);
2058
+ await client.injectProductElement([{ containerId: 'pdp', identifier: newId }]);
2059
+ }
2060
+
2061
+ // ✅ Components update automatically on state changes
2062
+ // Just inject once
2063
+ useEffect(() => {
2064
+ client.injectProductElement([{ containerId: 'pdp', identifier: productId }]);
2065
+ }, []); // Empty deps - inject once
2066
+
2067
+ // Product will auto-update when you call actions
2068
+ await client.actions.cart.addProduct([...]);
1114
2069
  ```
1115
- - Generates `CHANGELOG.md` from conventional commits
1116
- - Uses Angular commit convention
1117
- - **Use when:** Preparing releases
1118
2070
 
1119
- ### Build Configuration
2071
+ ### Cache Frequently Accessed Data
1120
2072
 
1121
- The build system uses **Rollup** with different configurations:
2073
+ ```js
2074
+ // ❌ Don't repeatedly fetch the same data
2075
+ async function showCartTotal() {
2076
+ const cart = await client.actions.cart.getDetails();
2077
+ return cart.total;
2078
+ }
2079
+
2080
+ // ✅ Use UI helpers that auto-update
2081
+ client.ui.cartSubtotal('cart-total-display');
2082
+ client.ui.cartItemsCount('cart-count-display');
2083
+
2084
+ // Or cache and listen to updates
2085
+ let cachedCart = await client.actions.cart.getDetails();
2086
+ window.addEventListener('lce:actions.cart_updated', (event) => {
2087
+ cachedCart = event.detail.data;
2088
+ });
2089
+ ```
1122
2090
 
1123
- #### ESM Build (`dist/index.esm.js`)
1124
- - **Target:** Modern bundlers (Vite, Webpack, etc.)
1125
- - **Format:** ES Modules
1126
- - **Optimizations:** Tree shaking, modern syntax
1127
- - **Use case:** NPM package imports
2091
+ ### Use CDN for Production
1128
2092
 
1129
- #### UMD Build (`umd/elements.js`)
1130
- - **Target:** Direct browser usage
1131
- - **Format:** Universal Module Definition
1132
- - **Global:** `window.LiquidCommerceElements`
1133
- - **Optimizations:** Maximum browser compatibility
1134
- - **Use case:** CDN distribution, `<script>` tags
2093
+ Always use CDN in production for optimal caching:
1135
2094
 
1136
- #### Development vs Production
1137
- - **Development:** Source maps, preserved logging, faster builds
1138
- - **Production:** Minified, compressed, optimized for size
2095
+ ```js
2096
+ // CDN (recommended)
2097
+ <script src="https://assets-elements.liquidcommerce.us/all/elements.js"></script>
1139
2098
 
1140
- ### Recommended Workflows
2099
+ // Don't self-host unless necessary
2100
+ <script src="/static/elements.js"></script>
2101
+ ```
1141
2102
 
1142
- **Development Workflow:**
1143
- ```bash
1144
- # Start development
1145
- pnpm run dev
2103
+ ### Minimize Theme Complexity
1146
2104
 
1147
- # Before committing
1148
- pnpm run fl
2105
+ Simpler themes = faster rendering:
2106
+
2107
+ ```js
2108
+ // ❌ Don't override every style property
2109
+ customTheme: {
2110
+ global: {
2111
+ colors: { /* 20 color overrides */ },
2112
+ typography: { /* 15 typography overrides */ },
2113
+ shadows: { /* 10 shadow overrides */ },
2114
+ // ... 100 more overrides
2115
+ }
2116
+ }
2117
+
2118
+ // ✅ Override only what's necessary
2119
+ customTheme: {
2120
+ global: {
2121
+ colors: {
2122
+ primary: '#007bff',
2123
+ secondary: '#6c757d'
2124
+ }
2125
+ }
2126
+ }
1149
2127
  ```
1150
2128
 
1151
- **Release Workflow:**
1152
- ```bash
1153
- # Clean and build for release
1154
- pnpm run clean:hard
2129
+ ### Monitor Performance
2130
+
2131
+ Track SDK performance in production:
2132
+
2133
+ ```js
2134
+ // Measure initialization time
2135
+ const start = performance.now();
2136
+ const client = await Elements('YOUR_API_KEY', { env: 'production' });
2137
+ console.log(`SDK initialized in ${performance.now() - start}ms`);
2138
+
2139
+ // Track component load times
2140
+ window.addEventListener('lce:actions.product_loaded', (event) => {
2141
+ const { loadTime } = event.detail.metadata;
2142
+ console.log(`Product loaded in ${loadTime}ms`);
2143
+
2144
+ // Send to analytics
2145
+ analytics.track('SDK Component Load', {
2146
+ component: 'product',
2147
+ duration: loadTime
2148
+ });
2149
+ });
2150
+ ```
2151
+
2152
+ ### Production Checklist
2153
+
2154
+ Before going live:
2155
+
2156
+ - ✅ Set `env: 'production'`
2157
+ - ✅ Set `debugMode: 'none'` (or omit)
2158
+ - ✅ Use CDN script URL
2159
+ - ✅ Pin to specific version (optional but recommended)
2160
+ - ✅ Configure proxy if using ad blockers
2161
+ - ✅ Test error handling
2162
+ - ✅ Verify event tracking
2163
+ - ✅ Check cart persistence
2164
+ - ✅ Test on target browsers
2165
+ - ✅ Measure performance metrics
1155
2166
 
1156
- # Generate changelog
1157
- pnpm run changelog
2167
+ **Production-ready init:**
1158
2168
 
1159
- # Build is run automatically on publish
2169
+ ```js
2170
+ const client = await Elements('YOUR_PRODUCTION_API_KEY', {
2171
+ env: 'production',
2172
+ debugMode: 'none',
2173
+ customTheme: { /* minimal overrides */ },
2174
+ proxy: { baseUrl: 'https://yourdomain.com/api/proxy' }
2175
+ });
1160
2176
  ```
1161
2177
 
1162
- **Troubleshooting:**
1163
- ```bash
1164
- # If builds are failing
1165
- pnpm run clean:hard
2178
+ **📖 For debugging and troubleshooting:** See [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for comprehensive problem-solving guide.
2179
+
2180
+ ---
1166
2181
 
1167
- # For code quality issues
1168
- pnpm run check
2182
+ ## 🔒 Proxy Configuration
2183
+
2184
+ Route API requests through your server to avoid ad blockers:
2185
+
2186
+ ```js
2187
+ const client = await Elements('YOUR_API_KEY', {
2188
+ env: 'production',
2189
+ proxy: {
2190
+ baseUrl: 'https://yourdomain.com/api/liquidcommerce',
2191
+ headers: {
2192
+ 'X-Custom-Header': 'value'
2193
+ }
2194
+ }
2195
+ });
1169
2196
  ```
1170
2197
 
2198
+ The SDK automatically handles routing and required headers. See [`docs/PROXY.md`](docs/PROXY.md) for complete proxy setup guide with Next.js examples.
2199
+
2200
+ ## 📚 Documentation
2201
+
2202
+ **📖 Complete Documentation:**
2203
+
2204
+ - **[Documentation Index](docs/DOCUMENTATION_INDEX.md)** - Complete guide to all documentation
2205
+ - **[Configuration Reference](docs/CONFIGURATION.md)** - All configuration options with TypeScript types
2206
+ - **[Theming Guide](docs/THEMING.md)** - Complete customization reference
2207
+ - **[Actions Reference](docs/ACTIONS.md)** - Programmatic control with business use cases
2208
+ - **[Events Reference](docs/EVENTS.md)** - Event system and tracking guide
2209
+ - **[Troubleshooting Guide](docs/TROUBLESHOOTING.md)** - Common issues and solutions
2210
+ - **[Browser Support](docs/BROWSER_SUPPORT.md)** - Detailed browser compatibility
2211
+ - **[Proxy Setup](docs/PROXY.md)** - Ad blocker avoidance configuration
2212
+
2213
+ ---
2214
+
2215
+ ## 🏷️ Versioning
2216
+
2217
+ This project uses Semantic Versioning. Two CDN environments are available:
2218
+
2219
+ - **Production:** `https://assets-elements.liquidcommerce.us/all/elements.js` (stable)
2220
+ - **Beta:** `https://assets-elements.liquidcommerce.us/all/beta/elements.js` (pre-release)
2221
+
1171
2222
  ## 💬 Support
1172
2223
 
1173
2224
  If you need help with your API key, environment selection, or implementation, contact your LiquidCommerce representative.