@liquidcommerce/elements-sdk 2.7.21 → 2.7.23
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 +1 -1
- package/dist/index.checkout.esm.js +7220 -7124
- package/dist/index.esm.js +11633 -11540
- package/dist/types/auto-initialize/shared-utils.d.ts +1 -0
- package/dist/types/clients/builder.d.ts +1 -1
- package/dist/types/clients/checkout.d.ts +1 -1
- package/dist/types/clients/main.d.ts +1 -1
- package/dist/types/core/pubsub/interfaces/address.interface.d.ts +3 -0
- package/dist/types/core/pubsub/interfaces/core.interface.d.ts +2 -2
- package/dist/types/utils/product.d.ts +5 -0
- package/docs/v1/api/actions/address-actions.md +20 -15
- package/docs/v1/api/actions/cart-actions.md +22 -23
- package/docs/v1/api/actions/checkout-actions.md +72 -25
- package/docs/v1/api/actions/product-actions.md +61 -15
- package/docs/v1/api/client.md +38 -14
- package/docs/v1/api/configuration.md +5 -1
- package/docs/v1/api/injection-methods.md +8 -4
- package/docs/v1/api/typescript-types.md +6 -0
- package/docs/v1/examples/advanced-patterns.md +7 -6
- package/docs/v1/examples/checkout-flow.md +1 -2
- package/docs/v1/getting-started/concepts.md +20 -25
- package/docs/v1/getting-started/installation.md +4 -4
- package/docs/v1/guides/address-component.md +12 -8
- package/docs/v1/guides/best-practices.md +5 -5
- package/docs/v1/guides/cart-component.md +27 -39
- package/docs/v1/guides/checkout-component.md +27 -29
- package/docs/v1/guides/events.md +4 -4
- package/docs/v1/guides/product-component.md +64 -19
- package/docs/v1/guides/product-list-component.md +8 -9
- package/docs/v1/guides/theming.md +6 -9
- package/docs/v1/integration/proxy-setup.md +22 -5
- package/docs/v1/reference/browser-support.md +2 -1
- package/docs/v1/reference/error-handling.md +12 -7
- package/docs/v1/reference/performance.md +1 -3
- package/docs/v1/reference/troubleshooting.md +3 -3
- package/package.json +9 -17
|
@@ -39,6 +39,7 @@ export declare function getProductUrlsConfig(): ProductUrlsConfig | undefined;
|
|
|
39
39
|
export declare function triggerAutoInit(initFunction: () => Promise<void>, errorPrefix: string): void;
|
|
40
40
|
export declare function setupCheckout(script: HTMLScriptElement, injectFn: (params: IInjectCheckoutParams) => Promise<IInjectedComponent | null>, exitCheckoutFn: () => void, options: {
|
|
41
41
|
errorPrefix: string;
|
|
42
|
+
warnIfMissing?: boolean;
|
|
42
43
|
}): Promise<void>;
|
|
43
44
|
export declare function setupExitCheckoutHandlers(exitCheckoutFn: () => void): void;
|
|
44
45
|
export declare function addProductViaQueryParam(actions: IQueryParamActions, script: HTMLScriptElement, errorPrefix: string): Promise<void>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ILiquidCommerceElementsBuilderClient } from '@/interfaces/client.interface';
|
|
2
2
|
import type { ILiquidCommerceElementsBuilderConfig } from '@/interfaces/config.interface';
|
|
3
|
-
export declare function ElementsBuilder(apiKey: string, config
|
|
3
|
+
export declare function ElementsBuilder(apiKey: string, config?: ILiquidCommerceElementsBuilderConfig): Promise<ILiquidCommerceElementsBuilderClient | null>;
|
|
@@ -3,4 +3,4 @@ import type { ILiquidCommerceElementsCheckoutClientConfig } from '@/interfaces/c
|
|
|
3
3
|
import '@/modules/theme-provider/styles/register-styles';
|
|
4
4
|
import '@/modules/address/styles/register-styles';
|
|
5
5
|
import '@/modules/checkout/styles/register-styles';
|
|
6
|
-
export declare function ElementsCheckout(apiKey: string, config
|
|
6
|
+
export declare function ElementsCheckout(apiKey: string, config?: ILiquidCommerceElementsCheckoutClientConfig): Promise<IElementsCheckoutClient | null>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ILiquidCommerceElementsClient } from '@/interfaces/client.interface';
|
|
2
2
|
import type { ILiquidCommerceElementsConfig } from '@/interfaces/config.interface';
|
|
3
|
-
export declare function Elements(apiKey: string, config
|
|
3
|
+
export declare function Elements(apiKey: string, config?: ILiquidCommerceElementsConfig): Promise<ILiquidCommerceElementsClient | null>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAddressActionEventData } from '@/core/pubsub/interfaces/address.interface';
|
|
1
|
+
import type { IAddressActionEventData, IAddressFailedEventData } from '@/core/pubsub/interfaces/address.interface';
|
|
2
2
|
import type { ICartFailedEventData, ICartItemAddedEventData, ICartItemEngravingUpdatedEventData, ICartItemQuantityChangedEventData, ICartItemRemovedEventData, ICartLoadedEventData, ICartProductAddEventData, ICartProductAddFailedEventData, ICartPromoCodeEventData, ICartPromoCodeFailedEventData, ICartUpdatedEventData } from '@/core/pubsub/interfaces/cart.interface';
|
|
3
3
|
import type { ICheckoutBillingInformationUpdatedEventData, ICheckoutCustomerInformationUpdatedEventData, ICheckoutFailedEventData, ICheckoutGiftCardEventData, ICheckoutGiftCardFailedEventData, ICheckoutGiftInformationUpdatedEventData, ICheckoutItemEngravingUpdatedEventData, ICheckoutItemQuantityChangedEventData, ICheckoutItemRemovedEventData, ICheckoutLoadedEventData, ICheckoutMarketingPreferencesToggleEventData, ICheckoutProductAddEventData, ICheckoutProductAddFailedEventData, ICheckoutPromoCodeEventData, ICheckoutPromoCodeFailedEventData, ICheckoutSubmitCompletedEventData, ICheckoutSubmitFailedEventData, ICheckoutSubmitStartedEventData, ICheckoutTipUpdatedEventData, ICheckoutToggleEventData } from '@/core/pubsub/interfaces/checkout.interface';
|
|
4
4
|
import type { IProductAddToCartEventData, IProductFulfillmentChangedEventData, IProductFulfillmentTypeChangedEventData, IProductLoadedEventData, IProductQuantityChangedEventData, IProductSizeChangedEventData } from '@/core/pubsub/interfaces/product.interface';
|
|
@@ -29,7 +29,7 @@ export interface IElementsActionsEventsMap {
|
|
|
29
29
|
[ELEMENTS_ACTIONS_EVENT.CLIENT_READY]: IElementsClientIsReadyEventData;
|
|
30
30
|
[ELEMENTS_ACTIONS_EVENT.ADDRESS_UPDATED]: IAddressActionEventData;
|
|
31
31
|
[ELEMENTS_ACTIONS_EVENT.ADDRESS_CLEARED]: boolean;
|
|
32
|
-
[ELEMENTS_ACTIONS_EVENT.ADDRESS_FAILED]:
|
|
32
|
+
[ELEMENTS_ACTIONS_EVENT.ADDRESS_FAILED]: IAddressFailedEventData;
|
|
33
33
|
[ELEMENTS_ACTIONS_EVENT.PRODUCT_LOADED]: IProductLoadedEventData;
|
|
34
34
|
[ELEMENTS_ACTIONS_EVENT.PRODUCT_QUANTITY_DECREASE]: IProductQuantityChangedEventData;
|
|
35
35
|
[ELEMENTS_ACTIONS_EVENT.PRODUCT_QUANTITY_INCREASE]: IProductQuantityChangedEventData;
|
|
@@ -7,4 +7,9 @@ export interface IPrepareApiProductForStoreParams {
|
|
|
7
7
|
retailers: IProductAvailabilityResponse['retailers'];
|
|
8
8
|
enableShippingFulfillment: boolean;
|
|
9
9
|
}
|
|
10
|
+
export declare function buildSizeLabel(size: {
|
|
11
|
+
size: string;
|
|
12
|
+
pack: boolean;
|
|
13
|
+
packDesc: string;
|
|
14
|
+
}): string;
|
|
10
15
|
export declare function prepareApiProductForStore({ context, product, retailers, enableShippingFulfillment, }: IPrepareApiProductForStoreParams): IProductStore | IPLProductStore;
|
|
@@ -49,11 +49,12 @@ setAddressManually(
|
|
|
49
49
|
|
|
50
50
|
```typescript
|
|
51
51
|
interface IAddressAddress {
|
|
52
|
-
one: string;
|
|
53
|
-
two
|
|
54
|
-
city: string;
|
|
55
|
-
state: string;
|
|
56
|
-
zip: string;
|
|
52
|
+
one: string; // Street address
|
|
53
|
+
two: string; // Apt, suite, etc.
|
|
54
|
+
city: string; // City name
|
|
55
|
+
state: string; // Two-letter state code
|
|
56
|
+
zip: string; // ZIP/postal code
|
|
57
|
+
country: string; // Country
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
interface IAddressCoordinates {
|
|
@@ -71,7 +72,8 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
71
72
|
two: 'Apt 4',
|
|
72
73
|
city: 'New York',
|
|
73
74
|
state: 'NY',
|
|
74
|
-
zip: '10001'
|
|
75
|
+
zip: '10001',
|
|
76
|
+
country: 'US'
|
|
75
77
|
},
|
|
76
78
|
{
|
|
77
79
|
latitude: 40.7128,
|
|
@@ -83,17 +85,19 @@ await window.LiquidCommerce.elements.actions.address.setAddressManually(
|
|
|
83
85
|
### Validation
|
|
84
86
|
|
|
85
87
|
The SDK validates:
|
|
86
|
-
- All required fields are present
|
|
87
|
-
- State is 2-letter code
|
|
88
|
+
- All required fields are present (street, city, state, zip)
|
|
88
89
|
- Latitude is between -90 and 90
|
|
89
90
|
- Longitude is between -180 and 180
|
|
90
91
|
|
|
92
|
+
> Note: the `state` field is expected to be a 2-letter code by convention, but the SDK does **not** enforce its format.
|
|
93
|
+
|
|
91
94
|
### Errors
|
|
92
95
|
|
|
93
96
|
**Throws `SDKError` if:**
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
+
- `address` or `coordinates` is missing
|
|
98
|
+
- A required field is missing (street, city, state, zip)
|
|
99
|
+
- Latitude or longitude is non-numeric
|
|
100
|
+
- Coordinates are out of range (latitude outside -90..90, longitude outside -180..180)
|
|
97
101
|
|
|
98
102
|
---
|
|
99
103
|
|
|
@@ -135,13 +139,14 @@ getDetails(): IAddressData | null
|
|
|
135
139
|
|
|
136
140
|
```typescript
|
|
137
141
|
interface IAddressData {
|
|
138
|
-
id: string; // Google Places ID
|
|
142
|
+
id: string; // Google Places ID (always populated when an object is returned)
|
|
139
143
|
address: {
|
|
140
144
|
one: string;
|
|
141
|
-
two
|
|
145
|
+
two: string;
|
|
142
146
|
city: string;
|
|
143
147
|
state: string;
|
|
144
148
|
zip: string;
|
|
149
|
+
country: string;
|
|
145
150
|
};
|
|
146
151
|
coordinates: {
|
|
147
152
|
latitude: number;
|
|
@@ -151,7 +156,7 @@ interface IAddressData {
|
|
|
151
156
|
}
|
|
152
157
|
```
|
|
153
158
|
|
|
154
|
-
Returns `null` if no address is set.
|
|
159
|
+
Returns `null` if no address is set. Manually-entered addresses (set via `setAddressManually`) are stored without a Google Places ID, so `getDetails()` also returns `null` for them.
|
|
155
160
|
|
|
156
161
|
### Example
|
|
157
162
|
|
|
@@ -194,7 +199,7 @@ Address actions trigger events:
|
|
|
194
199
|
```javascript
|
|
195
200
|
// Address updated
|
|
196
201
|
window.addEventListener('lce:actions.address_updated', (event) => {
|
|
197
|
-
const { address, coordinates, formattedAddress } = event.detail.data;
|
|
202
|
+
const { googlePlacesId, address, coordinates, formattedAddress } = event.detail.data;
|
|
198
203
|
console.log('Address set:', formattedAddress);
|
|
199
204
|
});
|
|
200
205
|
|
|
@@ -78,7 +78,7 @@ addProduct(params: IAddProductParams[], openCart?: boolean): Promise<void>
|
|
|
78
78
|
|
|
79
79
|
```typescript
|
|
80
80
|
interface IAddProductParams {
|
|
81
|
-
identifier: string; // Product UPC,
|
|
81
|
+
identifier: string; // Product UPC, size ID, or salsify grouping ID
|
|
82
82
|
fulfillmentType: FulfillmentType; // 'shipping' or 'onDemand'
|
|
83
83
|
quantity: number; // Number of items
|
|
84
84
|
engravingLines?: string[]; // Optional engraving (see below)
|
|
@@ -145,8 +145,8 @@ If no address is set, the SDK automatically:
|
|
|
145
145
|
- Identifier is invalid
|
|
146
146
|
- Fulfillment type is not `'shipping'` or `'onDemand'`
|
|
147
147
|
- Quantity is less than 1
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
|
|
149
|
+
Unavailable products and presale items are **not** thrown — they are silently skipped (a `cart.error` is set on the store). If no products could be added, a `cart_product_add_failed` event is emitted with `{ cartId, identifiers, error }` and the returned promise still resolves (it does not reject).
|
|
150
150
|
|
|
151
151
|
---
|
|
152
152
|
|
|
@@ -242,17 +242,17 @@ getDetails(): IBaseCartEventData
|
|
|
242
242
|
```typescript
|
|
243
243
|
interface IBaseCartEventData {
|
|
244
244
|
cartId: string;
|
|
245
|
-
|
|
245
|
+
promoCodeDiscount: number | null; // in cents
|
|
246
246
|
subtotal: number; // in cents
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
247
|
+
itemCount: number;
|
|
248
|
+
items: Record<string, ICartItem>; // keyed by item ID
|
|
249
|
+
retailers: Record<string, ICartRetailer>; // keyed by retailer ID
|
|
250
|
+
location: {
|
|
251
|
+
placesId: string;
|
|
252
|
+
formattedAddress: string;
|
|
253
|
+
address: IAddressAddress;
|
|
254
|
+
coordinates: IAddressCoordinates;
|
|
255
|
+
} | null;
|
|
256
256
|
}
|
|
257
257
|
```
|
|
258
258
|
|
|
@@ -262,12 +262,11 @@ interface IBaseCartEventData {
|
|
|
262
262
|
const cart = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
263
263
|
|
|
264
264
|
console.log(`Cart ID: ${cart.cartId}`);
|
|
265
|
-
console.log(`Items: ${cart.
|
|
265
|
+
console.log(`Items: ${cart.itemCount}`);
|
|
266
266
|
console.log(`Subtotal: $${cart.subtotal / 100}`);
|
|
267
|
-
console.log(`Total: $${cart.total / 100}`);
|
|
268
267
|
|
|
269
|
-
if (cart.
|
|
270
|
-
console.log(`Discount: $${cart.
|
|
268
|
+
if (cart.promoCodeDiscount) {
|
|
269
|
+
console.log(`Discount: $${cart.promoCodeDiscount / 100}`);
|
|
271
270
|
}
|
|
272
271
|
```
|
|
273
272
|
|
|
@@ -279,8 +278,8 @@ if (cart.promoCode) {
|
|
|
279
278
|
function updateCartSummary() {
|
|
280
279
|
const cart = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
281
280
|
|
|
282
|
-
document.getElementById('cart-count').textContent = cart.
|
|
283
|
-
document.getElementById('cart-total').textContent = `$${cart.
|
|
281
|
+
document.getElementById('cart-count').textContent = cart.itemCount;
|
|
282
|
+
document.getElementById('cart-total').textContent = `$${cart.subtotal / 100}`;
|
|
284
283
|
}
|
|
285
284
|
|
|
286
285
|
// Update on cart changes
|
|
@@ -293,7 +292,7 @@ window.addEventListener('lce:actions.cart_updated', updateCartSummary);
|
|
|
293
292
|
document.getElementById('checkout-btn').addEventListener('click', () => {
|
|
294
293
|
const cart = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
295
294
|
|
|
296
|
-
if (cart.
|
|
295
|
+
if (cart.itemCount === 0) {
|
|
297
296
|
alert('Your cart is empty');
|
|
298
297
|
return;
|
|
299
298
|
}
|
|
@@ -308,10 +307,10 @@ document.getElementById('checkout-btn').addEventListener('click', () => {
|
|
|
308
307
|
const cart = window.LiquidCommerce.elements.actions.cart.getDetails();
|
|
309
308
|
|
|
310
309
|
gtag('event', 'view_cart', {
|
|
311
|
-
value: cart.
|
|
310
|
+
value: cart.subtotal / 100,
|
|
312
311
|
currency: 'USD',
|
|
313
|
-
items: cart.items.map(item => ({
|
|
314
|
-
item_id: item.
|
|
312
|
+
items: Object.values(cart.items).map(item => ({
|
|
313
|
+
item_id: item.partNumber,
|
|
315
314
|
quantity: item.quantity
|
|
316
315
|
}))
|
|
317
316
|
});
|
|
@@ -60,7 +60,7 @@ window.LiquidCommerce.elements.actions.checkout.exitCheckout();
|
|
|
60
60
|
addProduct(params: IAddProductParams[], openCheckout?: boolean): Promise<void>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
Add products
|
|
63
|
+
Add products and open checkout in one call. Products are added to the cart (via the cart action, or directly when none is wired up), then checkout is prepared and opened. For a checkout without a cart session, use `addAnonymousProduct`.
|
|
64
64
|
|
|
65
65
|
`IAddProductParams.engravingLines?: string[]` — optional engraving. Same rules as [`actions.cart.addProduct()`](./cart-actions.md#actionscartaddproduct): invalid input is ignored, blanks stripped, lines clamped to the product's `maxLines` / `maxCharsPerLine`, and engraving is dropped (without failing) when the product, variant, or fulfillment doesn't support it.
|
|
66
66
|
|
|
@@ -94,15 +94,66 @@ addAnonymousProduct(
|
|
|
94
94
|
|
|
95
95
|
Add a product to checkout without requiring a cart session. Used for direct-to-checkout flows.
|
|
96
96
|
|
|
97
|
+
**Parameters** (`IAnonymousCheckoutAddProductParams`):
|
|
98
|
+
|
|
99
|
+
| Field | Type | Required | Description |
|
|
100
|
+
|-------|------|----------|-------------|
|
|
101
|
+
| `location` | `ILocation` | Yes | `{ address: IAddressAddress; coordinates: IAddressCoordinates }` |
|
|
102
|
+
| `items` | `IAnonymousCheckoutAddProductItem[]` | No | Products to add: `{ identifier, fulfillmentType, quantity }`. Provide `items` **or** `cartItems`. |
|
|
103
|
+
| `cartItems` | `ICartUpdateItem[]` | No | Pre-resolved cart line items: `{ id?, partNumber, quantity, fulfillmentId, engravingLines? }` (alternative to `items`). |
|
|
104
|
+
| `promoCode` | `string` | No | Promo code applied while creating the anonymous checkout. |
|
|
105
|
+
|
|
97
106
|
```javascript
|
|
98
107
|
const result = await window.LiquidCommerce.elements.actions.checkout
|
|
99
108
|
.addAnonymousProduct({
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
items: [
|
|
110
|
+
{ identifier: '00619947000020', fulfillmentType: 'shipping', quantity: 1 }
|
|
111
|
+
],
|
|
112
|
+
location: {
|
|
113
|
+
address: { one: '123 Main St', two: '', city: 'New York', state: 'NY', zip: '10001', country: 'US' },
|
|
114
|
+
coordinates: { latitude: 40.7128, longitude: -74.006 }
|
|
115
|
+
},
|
|
116
|
+
promoCode: 'WELCOME10' // optional
|
|
103
117
|
});
|
|
104
118
|
```
|
|
105
119
|
|
|
120
|
+
**Returns** (`IAnonymousCheckoutAddProductResponse`):
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
interface IAnonymousCheckoutAddProductResponse {
|
|
124
|
+
checkout: ICheckoutPrepare | null; // the prepared checkout (see below), or null on failure
|
|
125
|
+
unavailableItems: IAnonymousCheckoutUnavailableItem[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
interface IAnonymousCheckoutUnavailableItem {
|
|
129
|
+
identifier: string;
|
|
130
|
+
productName: string | null;
|
|
131
|
+
fulfillmentType: FulfillmentType; // 'shipping' | 'onDemand'
|
|
132
|
+
reason: 'product_not_available' | 'fulfillment_not_available';
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface ICheckoutPrepare {
|
|
136
|
+
token: string;
|
|
137
|
+
cartId: string;
|
|
138
|
+
customer: ICheckoutCustomer;
|
|
139
|
+
isGift: boolean;
|
|
140
|
+
billingSameAsShipping: boolean;
|
|
141
|
+
payment?: string;
|
|
142
|
+
giftOptions: ICheckoutGiftRecipient;
|
|
143
|
+
marketingPreferences: ICheckoutMarketingPreferences;
|
|
144
|
+
shippingAddress: ICheckoutShippingAddress;
|
|
145
|
+
billingAddress: ICheckoutBilling;
|
|
146
|
+
promoCode: ICheckoutPromoCode | null;
|
|
147
|
+
amounts: ICheckoutAmounts;
|
|
148
|
+
giftCards: ICheckoutGiftCard[];
|
|
149
|
+
presale: ICheckoutPresale | null;
|
|
150
|
+
itemsQuantity: number;
|
|
151
|
+
items: Record<string /* cart item ID */, ICheckoutItem>;
|
|
152
|
+
retailers: Record<string /* retailer ID */, ICheckoutRetailer>;
|
|
153
|
+
events: ICheckoutEvent[];
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
106
157
|
## Promo & Gift Card Actions
|
|
107
158
|
|
|
108
159
|
### actions.checkout.applyPromoCode()
|
|
@@ -219,7 +270,7 @@ Pre-fill customer information.
|
|
|
219
270
|
**Available fields:**
|
|
220
271
|
- `firstName`, `lastName`
|
|
221
272
|
- `email`, `phone`
|
|
222
|
-
- `
|
|
273
|
+
- `birthDate`, `addressTwo`
|
|
223
274
|
- `company`
|
|
224
275
|
|
|
225
276
|
```javascript
|
|
@@ -228,7 +279,7 @@ window.LiquidCommerce.elements.actions.checkout.updateCustomerInfo({
|
|
|
228
279
|
lastName: 'Doe',
|
|
229
280
|
email: 'john@example.com',
|
|
230
281
|
phone: '+15551234567',
|
|
231
|
-
|
|
282
|
+
birthDate: '1990-01-01',
|
|
232
283
|
addressTwo: 'Apt 4B',
|
|
233
284
|
company: 'Acme Corp'
|
|
234
285
|
});
|
|
@@ -341,7 +392,7 @@ const checkout = window.LiquidCommerce.elements.actions.checkout.getDetails();
|
|
|
341
392
|
|
|
342
393
|
console.log(`Cart ID: ${checkout.cartId}`);
|
|
343
394
|
console.log(`Total: $${checkout.amounts.total / 100}`);
|
|
344
|
-
console.log(`Items: ${checkout.
|
|
395
|
+
console.log(`Items: ${checkout.itemCount}`);
|
|
345
396
|
console.log(`Is Gift: ${checkout.isGift}`);
|
|
346
397
|
```
|
|
347
398
|
|
|
@@ -349,23 +400,19 @@ console.log(`Is Gift: ${checkout.isGift}`);
|
|
|
349
400
|
|
|
350
401
|
```typescript
|
|
351
402
|
interface ICheckoutDetailsEventData {
|
|
403
|
+
token: string;
|
|
352
404
|
cartId: string;
|
|
353
|
-
items: ICheckoutItem[];
|
|
354
|
-
amounts: {
|
|
355
|
-
subtotal: number;
|
|
356
|
-
tax: number;
|
|
357
|
-
shipping: number;
|
|
358
|
-
tip: number;
|
|
359
|
-
total: number;
|
|
360
|
-
};
|
|
361
|
-
customer: ICustomerInfo;
|
|
362
|
-
shippingAddress: IAddress;
|
|
363
|
-
billingAddress?: IAddress;
|
|
364
405
|
isGift: boolean;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
406
|
+
billingSameAsShipping: boolean;
|
|
407
|
+
marketingPreferences: {
|
|
408
|
+
canEmail: boolean;
|
|
409
|
+
canSms: boolean;
|
|
410
|
+
};
|
|
411
|
+
hasPromoCode: boolean;
|
|
412
|
+
hasGiftCards: boolean;
|
|
413
|
+
amounts: ICheckoutAmounts;
|
|
414
|
+
itemCount: number;
|
|
415
|
+
items: Record<string, ICheckoutItem>;
|
|
369
416
|
}
|
|
370
417
|
```
|
|
371
418
|
|
|
@@ -419,11 +466,11 @@ window.addEventListener('lce:actions.checkout_submit_started', () => {
|
|
|
419
466
|
});
|
|
420
467
|
|
|
421
468
|
window.addEventListener('lce:actions.checkout_submit_completed', (event) => {
|
|
422
|
-
const {
|
|
469
|
+
const { orderNumber, orderTotal } = event.detail.data;
|
|
423
470
|
|
|
424
471
|
gtag('event', 'purchase', {
|
|
425
|
-
transaction_id:
|
|
426
|
-
value:
|
|
472
|
+
transaction_id: orderNumber,
|
|
473
|
+
value: orderTotal / 100,
|
|
427
474
|
currency: 'USD'
|
|
428
475
|
});
|
|
429
476
|
});
|
|
@@ -21,19 +21,22 @@ getDetails(identifier: string): IBaseProductEventData
|
|
|
21
21
|
### Returns
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
|
+
// Inherits all IProduct fields except `sizes` (see below for the overridden `sizes` shape)
|
|
24
25
|
interface IBaseProductEventData {
|
|
25
26
|
identifier: string;
|
|
26
27
|
name: string;
|
|
27
28
|
description: string;
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
priceInfo: IProductPriceInfo | null; // { currency, minimum, average, maximum }
|
|
30
|
+
selectedSizeId: string | null;
|
|
30
31
|
selectedFulfillmentType: FulfillmentType;
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
selectedFulfillmentId: string | null;
|
|
33
|
+
productHasAvailability: boolean;
|
|
34
|
+
fulfillmentHasAvailability: boolean;
|
|
35
|
+
sizes: Record<string, IProductSizeEventData>;
|
|
33
36
|
images: string[];
|
|
34
37
|
brand: string;
|
|
35
38
|
category: string;
|
|
36
|
-
// ... additional fields
|
|
39
|
+
// ... additional IProduct fields
|
|
37
40
|
}
|
|
38
41
|
```
|
|
39
42
|
|
|
@@ -43,17 +46,16 @@ interface IBaseProductEventData {
|
|
|
43
46
|
const productData = window.LiquidCommerce.elements.actions.product.getDetails('00619947000020');
|
|
44
47
|
|
|
45
48
|
console.log(productData.name); // "Premium Whiskey"
|
|
46
|
-
console.log(productData.
|
|
47
|
-
console.log(productData.
|
|
48
|
-
console.log(productData.
|
|
49
|
+
console.log(productData.priceInfo?.minimum / 100); // 49.99
|
|
50
|
+
console.log(productData.sizes[productData.selectedSizeId]?.size); // "750ml"
|
|
51
|
+
console.log(productData.selectedSizeId); // "size_123"
|
|
49
52
|
```
|
|
50
53
|
|
|
51
54
|
### Errors
|
|
52
55
|
|
|
53
56
|
**Throws `SDKError` if:**
|
|
54
57
|
- Identifier is empty or invalid
|
|
55
|
-
- Product has not been loaded yet
|
|
56
|
-
- Product does not exist
|
|
58
|
+
- Product has not been loaded yet (a non-existent product surfaces as this same error)
|
|
57
59
|
|
|
58
60
|
```javascript
|
|
59
61
|
try {
|
|
@@ -71,7 +73,7 @@ try {
|
|
|
71
73
|
const product = window.LiquidCommerce.elements.actions.product.getDetails('00619947000020');
|
|
72
74
|
|
|
73
75
|
document.getElementById('product-name').textContent = product.name;
|
|
74
|
-
document.getElementById('product-price').textContent = `$${product.
|
|
76
|
+
document.getElementById('product-price').textContent = `$${product.priceInfo?.minimum / 100}`;
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
#### Sync with Analytics
|
|
@@ -84,7 +86,7 @@ window.addEventListener('lce:actions.product_loaded', () => {
|
|
|
84
86
|
items: [{
|
|
85
87
|
item_id: product.identifier,
|
|
86
88
|
item_name: product.name,
|
|
87
|
-
price: product.
|
|
89
|
+
price: product.priceInfo?.minimum / 100,
|
|
88
90
|
item_brand: product.brand
|
|
89
91
|
}]
|
|
90
92
|
});
|
|
@@ -97,7 +99,7 @@ window.addEventListener('lce:actions.product_loaded', () => {
|
|
|
97
99
|
const product1 = window.LiquidCommerce.elements.actions.product.getDetails('00619947000020');
|
|
98
100
|
const product2 = window.LiquidCommerce.elements.actions.product.getDetails('08504405135');
|
|
99
101
|
|
|
100
|
-
if (product1.
|
|
102
|
+
if (product1.priceInfo?.minimum < product2.priceInfo?.minimum) {
|
|
101
103
|
console.log(`${product1.name} is cheaper`);
|
|
102
104
|
}
|
|
103
105
|
```
|
|
@@ -124,14 +126,58 @@ getProductAvailabilityByState(
|
|
|
124
126
|
| `identifiers` | string[] | Yes | Array of product UPCs, SKUs, or IDs |
|
|
125
127
|
| `state` | string | No | Two-letter state code (e.g., `'NY'`) |
|
|
126
128
|
|
|
129
|
+
### Returns
|
|
130
|
+
|
|
131
|
+
Resolves to an `IProductAvailabilityResponse`:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
interface IProductAvailabilityResponse {
|
|
135
|
+
products: IProduct[];
|
|
136
|
+
retailers: Record<string /* retailer ID */, IRetailer>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
interface IRetailer {
|
|
140
|
+
id: string;
|
|
141
|
+
name: string;
|
|
142
|
+
address: IRetailerAddress; // IAddressAddress & IAddressCoordinates
|
|
143
|
+
addressFormatted: string;
|
|
144
|
+
shippingFulfillment: IFulfillment | null;
|
|
145
|
+
onDemandFulfillment: IFulfillment | null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface IFulfillment {
|
|
149
|
+
id: string;
|
|
150
|
+
type: FulfillmentType; // 'shipping' | 'onDemand'
|
|
151
|
+
doesAllowGiftCards: boolean;
|
|
152
|
+
doesAllowPromos: boolean;
|
|
153
|
+
expectation: string;
|
|
154
|
+
engravingExpectation: string;
|
|
155
|
+
fee: number;
|
|
156
|
+
timezone: string;
|
|
157
|
+
hourStatus: { isOpen: boolean; openTime: string; isClosed: boolean; closeTime: string };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface IProduct {
|
|
161
|
+
id: string; name: string; description: string; htmlDescription: string;
|
|
162
|
+
images: string[]; brand: string; region: string; country: string;
|
|
163
|
+
material: string; abv: string; proof: string; age: string; color: string;
|
|
164
|
+
flavor: string; variety: string; appellation: string; vintage: string;
|
|
165
|
+
tastingNotes: string; catPath: string; category: string; classification: string;
|
|
166
|
+
type: string; subType: string; salsifyGrouping: string;
|
|
167
|
+
priceInfo: IProductPriceInfo | null; // { currency, minimum, average, maximum } — cents
|
|
168
|
+
sizes: Record<string /* size ID */, IProductSize>;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
127
172
|
### Example
|
|
128
173
|
|
|
129
174
|
```javascript
|
|
130
175
|
// Check availability in a specific state
|
|
131
|
-
const
|
|
176
|
+
const availabilityCA = await window.LiquidCommerce.elements.actions.product
|
|
132
177
|
.getProductAvailabilityByState(['00619947000020', '08504405135'], 'CA');
|
|
133
178
|
|
|
134
|
-
//
|
|
179
|
+
// Omit the state to query without a state filter
|
|
180
|
+
// (state: undefined is sent — the SDK does NOT derive it from the stored address)
|
|
135
181
|
const availability = await window.LiquidCommerce.elements.actions.product
|
|
136
182
|
.getProductAvailabilityByState(['00619947000020']);
|
|
137
183
|
```
|
package/docs/v1/api/client.md
CHANGED
|
@@ -64,6 +64,36 @@ const client = await ElementsCheckout('YOUR_API_KEY', {
|
|
|
64
64
|
});
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
### ElementsBuilder()
|
|
68
|
+
|
|
69
|
+
Initialize the builder client, which exposes manual `inject*` / `update*` methods for fully programmatic composition.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
function ElementsBuilder(
|
|
73
|
+
apiKey: string,
|
|
74
|
+
config: ILiquidCommerceElementsBuilderConfig
|
|
75
|
+
): Promise<ILiquidCommerceElementsBuilderClient | null>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Parameters:**
|
|
79
|
+
|
|
80
|
+
| Parameter | Type | Required | Description |
|
|
81
|
+
|-----------|--------------------------------------|----------|-----------------------------|
|
|
82
|
+
| `apiKey` | string | Yes | Your LiquidCommerce API key |
|
|
83
|
+
| `config` | ILiquidCommerceElementsBuilderConfig | Yes | Builder configuration object (same shape as `ILiquidCommerceElementsConfig`) |
|
|
84
|
+
|
|
85
|
+
**Returns:** Promise that resolves to the builder client instance (`ILiquidCommerceElementsBuilderClient`), or `null` if initialization fails or it is called outside the browser.
|
|
86
|
+
|
|
87
|
+
**Example:**
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
import { ElementsBuilder } from '@liquidcommerce/elements-sdk';
|
|
91
|
+
|
|
92
|
+
const builder = await ElementsBuilder('YOUR_API_KEY', {
|
|
93
|
+
env: 'production'
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
67
97
|
## Configuration
|
|
68
98
|
|
|
69
99
|
### ILiquidCommerceElementsConfig
|
|
@@ -72,10 +102,8 @@ Complete configuration interface for the full SDK.
|
|
|
72
102
|
|
|
73
103
|
```typescript
|
|
74
104
|
interface ILiquidCommerceElementsConfig {
|
|
75
|
-
// Required
|
|
76
|
-
env: ElementsEnv; // 'development' | 'staging' | 'production'
|
|
77
|
-
|
|
78
105
|
// Optional
|
|
106
|
+
env?: ElementsEnv; // defaults to 'production' ('development' | 'staging' | 'production')
|
|
79
107
|
debugMode?: DebugMode; // 'none' | 'console' | 'panel'
|
|
80
108
|
customTheme?: IClientCustomThemeConfig;
|
|
81
109
|
promoTicker?: IPromoTicker[];
|
|
@@ -168,7 +196,7 @@ See [Proxy Setup Guide](../integration/proxy-setup.md) for implementation.
|
|
|
168
196
|
|
|
169
197
|
```typescript
|
|
170
198
|
interface ILiquidCommerceElementsCheckoutConfig {
|
|
171
|
-
pageUrl
|
|
199
|
+
pageUrl?: string; // Optional. URL pattern with {token} placeholder
|
|
172
200
|
}
|
|
173
201
|
```
|
|
174
202
|
|
|
@@ -186,6 +214,7 @@ checkout: {
|
|
|
186
214
|
interface ILiquidCommerceElementsDevelopmentConfig {
|
|
187
215
|
customApiUrl?: string;
|
|
188
216
|
openShadowDom?: boolean;
|
|
217
|
+
mockMode?: boolean; // enable mock data responses (sends 'X-Liquid-Api-Mock-Mode' header)
|
|
189
218
|
}
|
|
190
219
|
```
|
|
191
220
|
|
|
@@ -194,16 +223,18 @@ interface ILiquidCommerceElementsDevelopmentConfig {
|
|
|
194
223
|
```javascript
|
|
195
224
|
development: {
|
|
196
225
|
customApiUrl: 'http://localhost:3000/api',
|
|
197
|
-
openShadowDom: true //
|
|
226
|
+
openShadowDom: true // Use an OPEN (inspectable) Shadow DOM instead of the default closed mode; forced off in production
|
|
198
227
|
}
|
|
199
228
|
```
|
|
200
229
|
|
|
201
230
|
## Global Access
|
|
202
231
|
|
|
203
|
-
After initialization,
|
|
232
|
+
After initialization, each client is available globally under the `window.LiquidCommerce` namespace:
|
|
204
233
|
|
|
205
234
|
```javascript
|
|
206
|
-
window.LiquidCommerce.elements
|
|
235
|
+
window.LiquidCommerce.elements // full client (from Elements())
|
|
236
|
+
window.LiquidCommerce.elementsBuilder // builder client (from ElementsBuilder())
|
|
237
|
+
window.LiquidCommerce.elementsCheckout // checkout-only client (from ElementsCheckout())
|
|
207
238
|
```
|
|
208
239
|
|
|
209
240
|
This allows access from anywhere in your application:
|
|
@@ -397,13 +428,6 @@ import type {
|
|
|
397
428
|
IInjectCheckoutParams,
|
|
398
429
|
IInjectedComponent,
|
|
399
430
|
|
|
400
|
-
// Action types
|
|
401
|
-
IProductActions,
|
|
402
|
-
ICartActions,
|
|
403
|
-
ICheckoutActions,
|
|
404
|
-
IAddressActions,
|
|
405
|
-
IAddProductParams,
|
|
406
|
-
|
|
407
431
|
// Configuration types
|
|
408
432
|
IClientCustomThemeConfig,
|
|
409
433
|
IComponentGlobalConfigs,
|