@caldik/client 0.1.3 → 0.1.5
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 +164 -12
- package/dist/index.d.mts +60 -17
- package/dist/index.mjs +298 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# Caldik SDK
|
|
2
|
-
|
|
3
|
-
The official Caldik SDK for interacting with Caldik storefronts, products, carts, checkouts, and customer accounts.
|
|
2
|
+
TThe official Caldik SDK for interacting with Caldik storefronts, products, carts, checkouts, and customer accounts.
|
|
4
3
|
|
|
5
4
|
## Installation
|
|
6
5
|
|
|
@@ -37,9 +36,93 @@ const caldik = new CaldikClient({
|
|
|
37
36
|
|
|
38
37
|
> **Security:** Private API keys must only be used in trusted server-side environments. Never expose `sk_` keys in client-side code.
|
|
39
38
|
|
|
39
|
+
|
|
40
40
|
## Orders and Items
|
|
41
41
|
|
|
42
|
-
###
|
|
42
|
+
### List Products
|
|
43
|
+
|
|
44
|
+
Retrieve products associated with the current store.
|
|
45
|
+
|
|
46
|
+
**Basic usage**
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const { products } = await caldik.products.list()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Limit results**
|
|
53
|
+
|
|
54
|
+
Pass a number to limit the number of products returned.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const { products } = await caldik.products.list(20)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Get Product
|
|
61
|
+
|
|
62
|
+
Retrieve a visible product by its ID or slug. Product IDs are unambiguous. The
|
|
63
|
+
same slug can be used in different categories, but must be unique within a
|
|
64
|
+
category. Uncategorized products have their own shared slug namespace.
|
|
65
|
+
|
|
66
|
+
**Basic usage**
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const { product } = await caldik.products.get("PRODUCT_...")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Get a product by category and slug**
|
|
73
|
+
|
|
74
|
+
Pass a category ID or slug when the product slug is shared across categories.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const { product: rustProduct } = await caldik.products.get("stealth", {
|
|
78
|
+
category: "test2",
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const { product: testProduct } = await caldik.products.get("stealth", {
|
|
82
|
+
category: "test",
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Get a product by a unique slug**
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const { product } = await caldik.products.get("unique-product")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Get Store
|
|
93
|
+
|
|
94
|
+
**Get the store profile and statistics**
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const { store } = await caldik.store.get()
|
|
98
|
+
|
|
99
|
+
console.log(store.name)
|
|
100
|
+
console.log(store.averageRating) // e.g. 4.9; null when there are no reviews
|
|
101
|
+
console.log(store.orders) // integer count of all store order records
|
|
102
|
+
console.log(store.customers) // integer count of all customer records, including guests
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Read the store's social links**
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const { store } = await caldik.store.get()
|
|
109
|
+
|
|
110
|
+
const { instagram, tiktok, x, youtube, discord, telegram } = store.socials
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Socials are included in the same response. Each unconfigured link is `null`.
|
|
114
|
+
|
|
115
|
+
### Get Category
|
|
116
|
+
|
|
117
|
+
Retrieve a specific category by its ID.
|
|
118
|
+
|
|
119
|
+
**Basic usage**
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const { category } = await caldik.categories.get("CAT_ID")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### List Categories
|
|
43
126
|
|
|
44
127
|
Retrieve categories associated with the current store.
|
|
45
128
|
|
|
@@ -68,6 +151,8 @@ const { categories } = await caldik.categories.list({
|
|
|
68
151
|
})
|
|
69
152
|
```
|
|
70
153
|
|
|
154
|
+
**Optional fields**
|
|
155
|
+
|
|
71
156
|
The following fields are omitted by default unless explicitly requested using `include`:
|
|
72
157
|
|
|
73
158
|
| Field | Description |
|
|
@@ -75,16 +160,23 @@ The following fields are omitted by default unless explicitly requested using `i
|
|
|
75
160
|
| `productCount` | Number of products associated with the category. |
|
|
76
161
|
| `startingPrice` | Lowest available product price in the category, in cents. |
|
|
77
162
|
|
|
163
|
+
|
|
78
164
|
## Cart and Discounts
|
|
79
165
|
|
|
80
166
|
### Cart Management
|
|
81
167
|
|
|
82
|
-
|
|
168
|
+
**Get the cart**
|
|
169
|
+
|
|
170
|
+
Refresh the current items and applied discount from the server.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
const { items, discount } = await caldik.cart.get()
|
|
174
|
+
```
|
|
83
175
|
|
|
84
176
|
**Add an item**
|
|
85
177
|
|
|
86
178
|
```ts
|
|
87
|
-
const cart = caldik.cart.add({
|
|
179
|
+
const cart = await caldik.cart.add({
|
|
88
180
|
productId: "PRODUCT_...",
|
|
89
181
|
productVariantId: "PRODUCT_VARIANT_...",
|
|
90
182
|
quantity: 1,
|
|
@@ -93,30 +185,90 @@ const cart = caldik.cart.add({
|
|
|
93
185
|
|
|
94
186
|
**Update item quantity**
|
|
95
187
|
|
|
188
|
+
Set an item's quantity. A quantity of zero removes it.
|
|
189
|
+
|
|
96
190
|
```ts
|
|
97
|
-
caldik.cart.updateQuantity(cart.items[0].id, 3)
|
|
191
|
+
await caldik.cart.updateQuantity(cart.items[0].id, 3)
|
|
98
192
|
```
|
|
99
193
|
|
|
100
194
|
**Remove an item**
|
|
101
195
|
|
|
102
196
|
```ts
|
|
103
|
-
caldik.cart.remove(cart.items[0].id)
|
|
197
|
+
await caldik.cart.remove(cart.items[0].id)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Clear the cart**
|
|
201
|
+
|
|
202
|
+
Remove all items and the applied discount from the persisted cart.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
await caldik.cart.clear()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Check a discount**
|
|
209
|
+
|
|
210
|
+
Get a price and discount quote for the current items without applying the code.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
const quote = await caldik.cart.checkDiscount("SAVE10")
|
|
104
214
|
```
|
|
105
215
|
|
|
106
|
-
|
|
216
|
+
**Apply a discount**
|
|
107
217
|
|
|
108
|
-
|
|
218
|
+
Validate the code and save it to the current cart.
|
|
109
219
|
|
|
110
220
|
```ts
|
|
111
|
-
await caldik.cart.applyDiscount("SAVE10")
|
|
221
|
+
const discountedCart = await caldik.cart.applyDiscount("SAVE10")
|
|
112
222
|
```
|
|
113
223
|
|
|
114
|
-
|
|
224
|
+
**Remove the discount**
|
|
115
225
|
|
|
116
|
-
|
|
226
|
+
Remove the applied code while keeping the cart's items.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
await caldik.cart.removeDiscount()
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Checkout the cart**
|
|
233
|
+
|
|
234
|
+
Create an order using the persisted cart. The API revalidates prices and discounts.
|
|
117
235
|
|
|
118
236
|
```ts
|
|
119
237
|
const result = await caldik.cart.checkout({
|
|
238
|
+
paymentMethod: "stripe",
|
|
239
|
+
termsAccepted: acceptedTermsCheckbox,
|
|
240
|
+
successUrl: "https://shop.example/success",
|
|
241
|
+
cancelUrl: "https://shop.example/cart",
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Server-rendered Storefronts
|
|
246
|
+
|
|
247
|
+
Create a client for each incoming request so shopper sessions stay isolated.
|
|
248
|
+
Pass the request and forward returned session cookies to the outgoing response:
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
const responseHeaders = new Headers()
|
|
252
|
+
const caldik = new CaldikClient({
|
|
253
|
+
request,
|
|
254
|
+
onSetCookie: (cookie) => responseHeaders.append("Set-Cookie", cookie),
|
|
255
|
+
// External servers also supply storeId and their private apiKey.
|
|
256
|
+
})
|
|
257
|
+
const cart = await caldik.cart.get()
|
|
258
|
+
// Include responseHeaders in your framework's HTTP response.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Browser and server calls must share the same cookie context (for example through
|
|
262
|
+
a storefront API proxy). Cookies set only on a separate API hostname are not
|
|
263
|
+
included in requests to the storefront server. A private store key does not
|
|
264
|
+
replace a shopper's customer session.
|
|
265
|
+
|
|
266
|
+
### Checkout with Explicit Items
|
|
267
|
+
|
|
268
|
+
Use `caldik.checkout.create()` to create an order from explicitly provided items.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const result = await caldik.checkout.create({
|
|
120
272
|
paymentMethod: "stripe",
|
|
121
273
|
items: [
|
|
122
274
|
{
|
package/dist/index.d.mts
CHANGED
|
@@ -70,6 +70,25 @@ interface CategoryResponse {
|
|
|
70
70
|
interface Store {
|
|
71
71
|
name: string;
|
|
72
72
|
description: string;
|
|
73
|
+
/** Average of all store reviews, rounded to one decimal; null without reviews. */
|
|
74
|
+
averageRating: number | null;
|
|
75
|
+
/** All store order records, including unpaid, failed and refunded orders. */
|
|
76
|
+
orders: number;
|
|
77
|
+
/** All store customer records, including guest customers. */
|
|
78
|
+
customers: number;
|
|
79
|
+
socials: StoreSocials;
|
|
80
|
+
}
|
|
81
|
+
interface StoreSocials {
|
|
82
|
+
instagram: string | null;
|
|
83
|
+
tiktok: string | null;
|
|
84
|
+
x: string | null;
|
|
85
|
+
youtube: string | null;
|
|
86
|
+
discord: string | null;
|
|
87
|
+
telegram: string | null;
|
|
88
|
+
}
|
|
89
|
+
interface ProductGetOptions {
|
|
90
|
+
/** Category ID or slug. Required for a slug used in multiple categories. */
|
|
91
|
+
category?: string;
|
|
73
92
|
}
|
|
74
93
|
interface StoreResponse {
|
|
75
94
|
success: boolean;
|
|
@@ -349,6 +368,8 @@ interface RequestOptions {
|
|
|
349
368
|
edgeCache?: boolean;
|
|
350
369
|
/** Internal authorization policy. Protected hosted calls are the default. */
|
|
351
370
|
access?: "public" | "runtime";
|
|
371
|
+
/** Scoped credentials used by stateful storefront resources. */
|
|
372
|
+
headers?: Record<string, string>;
|
|
352
373
|
}
|
|
353
374
|
//#endregion
|
|
354
375
|
//#region src/internal/client.d.ts
|
|
@@ -356,13 +377,22 @@ type HttpClientOptions = {
|
|
|
356
377
|
apiKey?: string;
|
|
357
378
|
apiUrl?: string;
|
|
358
379
|
storeId?: string;
|
|
380
|
+
request?: Request;
|
|
381
|
+
onSetCookie?: (cookie: string) => void | Promise<void>;
|
|
359
382
|
};
|
|
360
383
|
declare class CaldikHttpClient {
|
|
361
384
|
private readonly apiKey?;
|
|
362
385
|
private readonly apiUrl;
|
|
363
386
|
private readonly storeId?;
|
|
387
|
+
private readonly cookies;
|
|
388
|
+
private readonly onSetCookie?;
|
|
389
|
+
private readonly authenticationListeners;
|
|
364
390
|
constructor(options?: HttpClientOptions);
|
|
365
391
|
storeContextId(): string | null;
|
|
392
|
+
hasCartSession(): boolean;
|
|
393
|
+
onCustomerAuthentication(listener: () => Promise<unknown>): void;
|
|
394
|
+
customerAuthenticated(): Promise<void>;
|
|
395
|
+
private captureCookies;
|
|
366
396
|
private baseUrl;
|
|
367
397
|
private request;
|
|
368
398
|
get<T>(path: string, params?: Record<string, string | number>, options?: RequestOptions): Promise<T>;
|
|
@@ -382,7 +412,7 @@ declare class ProductsApi {
|
|
|
382
412
|
private client;
|
|
383
413
|
constructor(client: CaldikHttpClient);
|
|
384
414
|
list(): Promise<ProductsResponse>;
|
|
385
|
-
get(productIdOrSlug: string): Promise<ProductResponse>;
|
|
415
|
+
get(productIdOrSlug: string, options?: ProductGetOptions): Promise<ProductResponse>;
|
|
386
416
|
}
|
|
387
417
|
//#endregion
|
|
388
418
|
//#region src/reviews.d.ts
|
|
@@ -476,10 +506,8 @@ declare class DiscountsApi {
|
|
|
476
506
|
}
|
|
477
507
|
//#endregion
|
|
478
508
|
//#region src/cart.d.ts
|
|
479
|
-
interface CartItem {
|
|
509
|
+
interface CartItem extends ProductCommerceItem {
|
|
480
510
|
id: string;
|
|
481
|
-
productId: string;
|
|
482
|
-
productVariantId?: string;
|
|
483
511
|
quantity: number;
|
|
484
512
|
}
|
|
485
513
|
interface CartDiscount {
|
|
@@ -494,24 +522,35 @@ interface CartSnapshot {
|
|
|
494
522
|
items: CartItem[];
|
|
495
523
|
discount: CartDiscount | null;
|
|
496
524
|
}
|
|
497
|
-
type CartCheckoutInput = Omit<CreateOrderInput, "items" | "discountCode">;
|
|
525
|
+
type CartCheckoutInput = Omit<CreateOrderInput, "items" | "discountCode" | "customerId">;
|
|
526
|
+
/** One persisted cart, automatically scoped to the current shopper session. */
|
|
498
527
|
declare class CartApi {
|
|
499
528
|
private client;
|
|
500
|
-
private
|
|
529
|
+
private cache;
|
|
530
|
+
private queue;
|
|
531
|
+
private initialized;
|
|
501
532
|
constructor(client: CaldikHttpClient);
|
|
502
|
-
private
|
|
503
|
-
private
|
|
533
|
+
private storage;
|
|
534
|
+
private key;
|
|
535
|
+
private readCache;
|
|
536
|
+
private persistCache;
|
|
504
537
|
private write;
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
private
|
|
538
|
+
private enqueue;
|
|
539
|
+
private options;
|
|
540
|
+
private resolve;
|
|
541
|
+
private reset;
|
|
542
|
+
private mutate;
|
|
543
|
+
private save;
|
|
544
|
+
private quote;
|
|
545
|
+
get(): Promise<CartSnapshot>;
|
|
546
|
+
add(item: ProductCommerceItem): Promise<CartSnapshot>;
|
|
547
|
+
updateQuantity(itemId: string, nextQuantity: number): Promise<CartSnapshot>;
|
|
548
|
+
remove(itemId: string): Promise<CartSnapshot>;
|
|
549
|
+
clear(): Promise<CartSnapshot>;
|
|
511
550
|
checkDiscount(code: string): Promise<DiscountQuoteResponse>;
|
|
512
551
|
applyDiscount(code: string): Promise<CartSnapshot>;
|
|
513
|
-
removeDiscount(): CartSnapshot
|
|
514
|
-
checkout(input
|
|
552
|
+
removeDiscount(): Promise<CartSnapshot>;
|
|
553
|
+
checkout(input?: CartCheckoutInput): Promise<OrderResponse>;
|
|
515
554
|
}
|
|
516
555
|
//#endregion
|
|
517
556
|
//#region src/index.d.ts
|
|
@@ -521,6 +560,10 @@ interface CaldikClientOptions {
|
|
|
521
560
|
/** Private API key for external server integrations. Never use in browsers. */
|
|
522
561
|
apiKey?: string;
|
|
523
562
|
apiUrl?: string;
|
|
563
|
+
/** Incoming storefront request. Create one client per server request to isolate shoppers. */
|
|
564
|
+
request?: Request;
|
|
565
|
+
/** Forward session cookies to the outgoing storefront response in server code. */
|
|
566
|
+
onSetCookie?: (cookie: string) => void | Promise<void>;
|
|
524
567
|
}
|
|
525
568
|
declare class CaldikClient {
|
|
526
569
|
readonly categories: CategoriesApi;
|
|
@@ -535,4 +578,4 @@ declare class CaldikClient {
|
|
|
535
578
|
constructor(options?: CaldikClientOptions);
|
|
536
579
|
}
|
|
537
580
|
//#endregion
|
|
538
|
-
export { AppliedDiscount, CaldikClient, CaldikClientOptions, CartApi, CartCheckoutInput, CartDiscount, CartItem, CartSnapshot, CategoriesResponse, Category, CategoryDetails, CategoryInclude, CategoryListOptions, CategoryMetadata, CategoryProduct, CategoryResponse, CheckDiscountInput, CheckoutPayment, CheckoutPaymentMethod, CheckoutPaymentMethodsResponse, CheckoutPaymentProviderId, CheckoutSettings, CheckoutSettingsResponse, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerEmailLoginInput, CustomerLoginResponse, CustomerLoginSettings, CustomerLoginSettingsResponse, CustomerLoginVerifyResponse, CustomerPasswordInput, CustomerPasswordResetInput, CustomerPasswordResetResponse, CustomerPasswordResetVerifyResponse, CustomerPasswordResponse, CustomerProfileResponse, CustomerRegistrationInput, CustomerRegistrationResponse, CustomerSessionResponse, DiscountQuoteResponse, DiscountsApi, ManualCommerceItem, OrderResponse, PaymentProviderId, Product, ProductCommerceItem, ProductCustomField, ProductCustomFieldInputType, ProductCustomFieldOption, ProductMetadata, ProductResponse, ProductTag, ProductVariant, ProductsResponse, Review, ReviewsResponse, Store, StoreResponse, StoreWebhookEvent, StoreWebhookEventName, StorefrontMetadata, StorefrontOrder, SubscriptionPaymentProviderId, SubscriptionResponse, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|
|
581
|
+
export { AppliedDiscount, CaldikClient, CaldikClientOptions, CartApi, CartCheckoutInput, CartDiscount, CartItem, CartSnapshot, CategoriesResponse, Category, CategoryDetails, CategoryInclude, CategoryListOptions, CategoryMetadata, CategoryProduct, CategoryResponse, CheckDiscountInput, CheckoutPayment, CheckoutPaymentMethod, CheckoutPaymentMethodsResponse, CheckoutPaymentProviderId, CheckoutSettings, CheckoutSettingsResponse, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerEmailLoginInput, CustomerLoginResponse, CustomerLoginSettings, CustomerLoginSettingsResponse, CustomerLoginVerifyResponse, CustomerPasswordInput, CustomerPasswordResetInput, CustomerPasswordResetResponse, CustomerPasswordResetVerifyResponse, CustomerPasswordResponse, CustomerProfileResponse, CustomerRegistrationInput, CustomerRegistrationResponse, CustomerSessionResponse, DiscountQuoteResponse, DiscountsApi, ManualCommerceItem, OrderResponse, PaymentProviderId, Product, ProductCommerceItem, ProductCustomField, ProductCustomFieldInputType, ProductCustomFieldOption, ProductGetOptions, ProductMetadata, ProductResponse, ProductTag, ProductVariant, ProductsResponse, Review, ReviewsResponse, Store, StoreResponse, StoreSocials, StoreWebhookEvent, StoreWebhookEventName, StorefrontMetadata, StorefrontOrder, SubscriptionPaymentProviderId, SubscriptionResponse, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|
package/dist/index.mjs
CHANGED
|
@@ -26,6 +26,14 @@ function defaultApiUrl(browser) {
|
|
|
26
26
|
//#region src/internal/client.ts
|
|
27
27
|
const STORE_ID_PATTERN = /^STORE_[a-f0-9]{32}$/i;
|
|
28
28
|
const STOREFRONT_STORE_ID_ATTRIBUTE = "data-caldik-store-id";
|
|
29
|
+
var CaldikHttpError = class extends Error {
|
|
30
|
+
status;
|
|
31
|
+
constructor(message, status) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.status = status;
|
|
34
|
+
this.name = "CaldikHttpError";
|
|
35
|
+
}
|
|
36
|
+
};
|
|
29
37
|
function isBrowserRuntime() {
|
|
30
38
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
31
39
|
}
|
|
@@ -48,9 +56,17 @@ var CaldikHttpClient = class {
|
|
|
48
56
|
apiKey;
|
|
49
57
|
apiUrl;
|
|
50
58
|
storeId;
|
|
59
|
+
cookies = /* @__PURE__ */ new Map();
|
|
60
|
+
onSetCookie;
|
|
61
|
+
authenticationListeners = /* @__PURE__ */ new Set();
|
|
51
62
|
constructor(options = {}) {
|
|
52
63
|
this.apiKey = options.apiKey?.trim() || void 0;
|
|
53
64
|
this.apiUrl = options.apiUrl || defaultApiUrl(isBrowserRuntime());
|
|
65
|
+
this.onSetCookie = options.onSetCookie;
|
|
66
|
+
if (!isBrowserRuntime()) for (const part of (options.request?.headers.get("Cookie") || "").split(";")) {
|
|
67
|
+
const separator = part.indexOf("=");
|
|
68
|
+
if (separator > 0) this.cookies.set(part.slice(0, separator).trim(), part.slice(separator + 1).trim());
|
|
69
|
+
}
|
|
54
70
|
const configuredStoreId = options.storeId?.trim() || void 0;
|
|
55
71
|
if (this.apiKey && !this.apiKey.startsWith("sk_")) throw new Error("Caldik external integrations require a private sk_ API key");
|
|
56
72
|
if (configuredStoreId && !STORE_ID_PATTERN.test(configuredStoreId)) throw new Error("Caldik storeId is invalid");
|
|
@@ -60,6 +76,31 @@ var CaldikHttpClient = class {
|
|
|
60
76
|
storeContextId() {
|
|
61
77
|
return this.storeId || boundRuntimeStoreId();
|
|
62
78
|
}
|
|
79
|
+
hasCartSession() {
|
|
80
|
+
return this.cookies.has(`caldik_cart_session_${this.storeContextId()}`);
|
|
81
|
+
}
|
|
82
|
+
onCustomerAuthentication(listener) {
|
|
83
|
+
this.authenticationListeners.add(listener);
|
|
84
|
+
}
|
|
85
|
+
async customerAuthenticated() {
|
|
86
|
+
await Promise.allSettled([...this.authenticationListeners].map((listener) => listener()));
|
|
87
|
+
}
|
|
88
|
+
async captureCookies(response) {
|
|
89
|
+
for (const cookie of response.headers.getSetCookie()) {
|
|
90
|
+
const [pair = "", ...attributes] = cookie.split(";");
|
|
91
|
+
const separator = pair.indexOf("=");
|
|
92
|
+
if (separator < 1) continue;
|
|
93
|
+
const name = pair.slice(0, separator).trim();
|
|
94
|
+
if (attributes.some((attribute) => {
|
|
95
|
+
const [key, ...value] = attribute.trim().split("=");
|
|
96
|
+
if (key?.toLowerCase() === "max-age") return Number(value.join("=")) <= 0;
|
|
97
|
+
if (key?.toLowerCase() === "expires") return Date.parse(value.join("=")) <= Date.now();
|
|
98
|
+
return false;
|
|
99
|
+
})) this.cookies.delete(name);
|
|
100
|
+
else this.cookies.set(name, pair.slice(separator + 1).trim());
|
|
101
|
+
await this.onSetCookie?.(cookie);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
63
104
|
baseUrl() {
|
|
64
105
|
if (isBrowserRuntime()) {
|
|
65
106
|
const storeId = this.storeId;
|
|
@@ -76,8 +117,9 @@ var CaldikHttpClient = class {
|
|
|
76
117
|
async request(method, path, input, params, options) {
|
|
77
118
|
const url = new URL(`${this.baseUrl()}${path}`);
|
|
78
119
|
if (params) for (const [key, value] of Object.entries(params)) url.searchParams.set(key, String(value));
|
|
79
|
-
const headers = {};
|
|
120
|
+
const headers = { ...options?.headers };
|
|
80
121
|
if (!isBrowserRuntime()) headers["User-Agent"] = "CaldikClient/0.0.2";
|
|
122
|
+
if (!isBrowserRuntime() && options?.access === "public" && this.cookies.size) headers.Cookie = [...this.cookies].map(([name, value]) => `${name}=${value}`).join("; ");
|
|
81
123
|
if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;
|
|
82
124
|
else if (options?.access === "public" && (!isBrowserRuntime() || isLocalBrowserRuntime())) headers["X-Caldik-Public-Request"] = "1";
|
|
83
125
|
if (input !== void 0) headers["Content-Type"] = "application/json";
|
|
@@ -89,10 +131,10 @@ var CaldikHttpClient = class {
|
|
|
89
131
|
cache: "default",
|
|
90
132
|
credentials: "include"
|
|
91
133
|
});
|
|
134
|
+
if (!isBrowserRuntime() && options?.access === "public") await this.captureCookies(response);
|
|
92
135
|
if (!response.ok) {
|
|
93
136
|
const error = await response.clone().json().catch(() => null);
|
|
94
|
-
|
|
95
|
-
throw new Error(message);
|
|
137
|
+
throw new CaldikHttpError(typeof error?.message === "string" && error.message ? error.message : `${response.status} ${response.statusText}`.trim(), response.status);
|
|
96
138
|
}
|
|
97
139
|
return response.json();
|
|
98
140
|
}
|
|
@@ -131,8 +173,8 @@ var ProductsApi = class {
|
|
|
131
173
|
list() {
|
|
132
174
|
return this.client.get("/products", void 0, { access: "public" });
|
|
133
175
|
}
|
|
134
|
-
get(productIdOrSlug) {
|
|
135
|
-
return this.client.get(`/products/${encodeURIComponent(productIdOrSlug)}`, void 0, { access: "public" });
|
|
176
|
+
get(productIdOrSlug, options) {
|
|
177
|
+
return this.client.get(`/products/${encodeURIComponent(productIdOrSlug)}`, options?.category === void 0 ? void 0 : { category: options.category }, { access: "public" });
|
|
136
178
|
}
|
|
137
179
|
};
|
|
138
180
|
//#endregion
|
|
@@ -207,7 +249,11 @@ var CustomerApi = class {
|
|
|
207
249
|
};
|
|
208
250
|
let pendingChallengeId;
|
|
209
251
|
async function login(input, options) {
|
|
210
|
-
if (typeof input !== "string" && "password" in input)
|
|
252
|
+
if (typeof input !== "string" && "password" in input) {
|
|
253
|
+
const response = await client.post("/customers/login/password", input, { access: "public" });
|
|
254
|
+
await client.customerAuthenticated();
|
|
255
|
+
return response;
|
|
256
|
+
}
|
|
211
257
|
const response = await client.post("/customers/login", typeof input === "string" ? {
|
|
212
258
|
email: input,
|
|
213
259
|
...options
|
|
@@ -225,6 +271,7 @@ verify: async (code, challengeId = pendingChallengeId) => {
|
|
|
225
271
|
challengeId
|
|
226
272
|
}, { access: "public" });
|
|
227
273
|
if (pendingChallengeId === challengeId) pendingChallengeId = void 0;
|
|
274
|
+
await client.customerAuthenticated();
|
|
228
275
|
return response;
|
|
229
276
|
} });
|
|
230
277
|
let pendingRegistrationId;
|
|
@@ -243,6 +290,7 @@ verify: async (code, challengeId = pendingRegistrationId) => {
|
|
|
243
290
|
challengeId
|
|
244
291
|
}, { access: "public" });
|
|
245
292
|
if (pendingRegistrationId === challengeId) pendingRegistrationId = void 0;
|
|
293
|
+
await client.customerAuthenticated();
|
|
246
294
|
return response;
|
|
247
295
|
} });
|
|
248
296
|
}
|
|
@@ -279,20 +327,18 @@ var DiscountsApi = class {
|
|
|
279
327
|
};
|
|
280
328
|
//#endregion
|
|
281
329
|
//#region src/cart.ts
|
|
282
|
-
const CART_VERSION = 1;
|
|
283
330
|
const MAX_QUANTITY = 999999;
|
|
284
|
-
function
|
|
285
|
-
return item.productVariantId ? `${item.productId}:${item.productVariantId}` : item.productId;
|
|
286
|
-
}
|
|
287
|
-
function quantity(value, allowZero = false) {
|
|
288
|
-
const normalized = value ?? 1;
|
|
331
|
+
function quantity(value = 1, allowZero = false) {
|
|
289
332
|
const minimum = allowZero ? 0 : 1;
|
|
290
|
-
if (!Number.isInteger(
|
|
291
|
-
return
|
|
333
|
+
if (!Number.isInteger(value) || value < minimum || value > MAX_QUANTITY) throw new Error(`Cart quantity must be an integer between ${minimum} and ${MAX_QUANTITY}`);
|
|
334
|
+
return value;
|
|
292
335
|
}
|
|
293
336
|
function cloneSnapshot(state) {
|
|
294
337
|
return {
|
|
295
|
-
items: state.items.map((item) => ({
|
|
338
|
+
items: state.items.map((item) => ({
|
|
339
|
+
...item,
|
|
340
|
+
...item.customFields ? { customFields: { ...item.customFields } } : {}
|
|
341
|
+
})),
|
|
296
342
|
discount: state.discount ? { ...state.discount } : null
|
|
297
343
|
};
|
|
298
344
|
}
|
|
@@ -303,140 +349,267 @@ function isCartItem(value) {
|
|
|
303
349
|
}
|
|
304
350
|
function isCartDiscount(value) {
|
|
305
351
|
if (!value || typeof value !== "object") return false;
|
|
306
|
-
|
|
307
|
-
|
|
352
|
+
return [
|
|
353
|
+
"code",
|
|
354
|
+
"percentage",
|
|
355
|
+
"subtotal",
|
|
356
|
+
"discountAmount",
|
|
357
|
+
"total",
|
|
358
|
+
"currency"
|
|
359
|
+
].every((key) => typeof value[key] === "string");
|
|
308
360
|
}
|
|
361
|
+
function isReference(value) {
|
|
362
|
+
if (!value || typeof value !== "object") return false;
|
|
363
|
+
const reference = value;
|
|
364
|
+
return typeof reference.id === "string" && /^CART_[a-f0-9]{32}$/.test(reference.id) && (reference.token == null || typeof reference.token === "string");
|
|
365
|
+
}
|
|
366
|
+
function commerceItems(items) {
|
|
367
|
+
return items.map(({ id: _id, ...item }) => item);
|
|
368
|
+
}
|
|
369
|
+
function discountFromQuote(quote) {
|
|
370
|
+
return {
|
|
371
|
+
...quote.discount,
|
|
372
|
+
subtotal: quote.subtotal,
|
|
373
|
+
discountAmount: quote.discountAmount,
|
|
374
|
+
total: quote.total,
|
|
375
|
+
currency: quote.currency
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/** One persisted cart, automatically scoped to the current shopper session. */
|
|
309
379
|
var CartApi = class {
|
|
310
380
|
client;
|
|
311
|
-
|
|
312
|
-
version:
|
|
313
|
-
|
|
314
|
-
|
|
381
|
+
cache = {
|
|
382
|
+
version: 2,
|
|
383
|
+
reference: null,
|
|
384
|
+
snapshot: {
|
|
385
|
+
items: [],
|
|
386
|
+
discount: null
|
|
387
|
+
}
|
|
315
388
|
};
|
|
389
|
+
queue = Promise.resolve();
|
|
390
|
+
initialized = false;
|
|
316
391
|
constructor(client) {
|
|
317
392
|
this.client = client;
|
|
393
|
+
client.onCustomerAuthentication(() => {
|
|
394
|
+
this.readCache();
|
|
395
|
+
return this.initialized || this.cache.reference || this.cache.snapshot.items.length || client.hasCartSession() ? this.enqueue(async () => {
|
|
396
|
+
await this.resolve();
|
|
397
|
+
}) : Promise.resolve();
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
storage() {
|
|
401
|
+
try {
|
|
402
|
+
return typeof window !== "undefined" && typeof document !== "undefined" && typeof localStorage !== "undefined" ? localStorage : null;
|
|
403
|
+
} catch {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
318
406
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
if (
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
330
|
-
version:
|
|
407
|
+
key() {
|
|
408
|
+
return `caldik:cart:${this.client.storeContextId()}`;
|
|
409
|
+
}
|
|
410
|
+
readCache() {
|
|
411
|
+
const storage = this.storage();
|
|
412
|
+
if (!storage) return;
|
|
413
|
+
try {
|
|
414
|
+
const parsed = JSON.parse(storage.getItem(this.key()) || "null");
|
|
415
|
+
if (parsed?.version === 2) {
|
|
416
|
+
const snapshot = parsed.snapshot;
|
|
417
|
+
if (snapshot && Array.isArray(snapshot.items) && snapshot.items.every(isCartItem) && (parsed.reference === null || isReference(parsed.reference))) this.cache = {
|
|
418
|
+
version: 2,
|
|
419
|
+
reference: parsed.reference,
|
|
420
|
+
snapshot: cloneSnapshot({
|
|
421
|
+
items: snapshot.items,
|
|
422
|
+
discount: isCartDiscount(snapshot.discount) ? snapshot.discount : null
|
|
423
|
+
})
|
|
424
|
+
};
|
|
425
|
+
} else if (parsed?.version === 1 && Array.isArray(parsed.items) && parsed.items.every(isCartItem)) this.cache = {
|
|
426
|
+
version: 2,
|
|
427
|
+
reference: null,
|
|
428
|
+
snapshot: cloneSnapshot({
|
|
331
429
|
items: parsed.items,
|
|
332
430
|
discount: isCartDiscount(parsed.discount) ? parsed.discount : null
|
|
333
|
-
}
|
|
431
|
+
})
|
|
432
|
+
};
|
|
433
|
+
if (!this.cache.reference) {
|
|
434
|
+
const legacy = JSON.parse(storage.getItem(`caldik:server-cart:${this.client.storeContextId()}`) || "null");
|
|
435
|
+
if (isReference(legacy)) this.cache.reference = legacy;
|
|
334
436
|
}
|
|
335
437
|
} catch {}
|
|
336
|
-
return this.memory;
|
|
337
438
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const key = this.storageKey();
|
|
344
|
-
if (key && typeof localStorage !== "undefined") try {
|
|
345
|
-
localStorage.setItem(key, JSON.stringify(this.memory));
|
|
439
|
+
persistCache() {
|
|
440
|
+
try {
|
|
441
|
+
const storage = this.storage();
|
|
442
|
+
storage?.setItem(this.key(), JSON.stringify(this.cache));
|
|
443
|
+
storage?.removeItem(`caldik:server-cart:${this.client.storeContextId()}`);
|
|
346
444
|
} catch {}
|
|
347
|
-
|
|
445
|
+
}
|
|
446
|
+
write(cart, token = this.cache.reference?.token, discount = null) {
|
|
447
|
+
this.cache = {
|
|
448
|
+
version: 2,
|
|
449
|
+
reference: {
|
|
450
|
+
id: cart.id,
|
|
451
|
+
token: cart.customerId ? null : token
|
|
452
|
+
},
|
|
453
|
+
snapshot: cloneSnapshot({
|
|
454
|
+
items: cart.items,
|
|
455
|
+
discount
|
|
456
|
+
})
|
|
457
|
+
};
|
|
458
|
+
this.persistCache();
|
|
459
|
+
return cloneSnapshot(this.cache.snapshot);
|
|
460
|
+
}
|
|
461
|
+
enqueue(operation) {
|
|
462
|
+
const run = () => {
|
|
463
|
+
const locks = this.storage() && typeof navigator !== "undefined" ? navigator.locks : void 0;
|
|
464
|
+
return locks ? locks.request(this.key(), operation) : operation();
|
|
465
|
+
};
|
|
466
|
+
const result = this.queue.then(run, run);
|
|
467
|
+
this.queue = result.catch(() => void 0);
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
470
|
+
options() {
|
|
471
|
+
return {
|
|
472
|
+
access: "public",
|
|
473
|
+
...this.cache.reference?.token ? { headers: { "X-Caldik-Cart-Token": this.cache.reference.token } } : {}
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
async resolve(checkout = false, seed = true) {
|
|
477
|
+
this.readCache();
|
|
478
|
+
const input = this.cache.reference ? { cartId: this.cache.reference.id } : seed && this.cache.snapshot.items.length ? {
|
|
479
|
+
items: commerceItems(this.cache.snapshot.items),
|
|
480
|
+
discountCode: this.cache.snapshot.discount?.code
|
|
481
|
+
} : {};
|
|
482
|
+
const response = await this.client.post("/carts/session", {
|
|
483
|
+
...input,
|
|
484
|
+
...checkout ? { checkout: true } : {}
|
|
485
|
+
}, this.options());
|
|
486
|
+
this.initialized = true;
|
|
487
|
+
this.write(response.cart, response.token ?? null);
|
|
488
|
+
if (!checkout && response.cart.status === "checked_out") {
|
|
489
|
+
this.reset();
|
|
490
|
+
return this.resolve(false, false);
|
|
491
|
+
}
|
|
492
|
+
return response.cart;
|
|
493
|
+
}
|
|
494
|
+
reset() {
|
|
495
|
+
this.cache = {
|
|
496
|
+
version: 2,
|
|
497
|
+
reference: null,
|
|
498
|
+
snapshot: {
|
|
499
|
+
items: [],
|
|
500
|
+
discount: null
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
this.persistCache();
|
|
504
|
+
}
|
|
505
|
+
async mutate(operation, seed = true) {
|
|
506
|
+
let cart = await this.resolve(false, seed);
|
|
507
|
+
let response;
|
|
508
|
+
try {
|
|
509
|
+
response = await operation(cart);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
if (!(error instanceof CaldikHttpError) || error.status !== 409) throw error;
|
|
512
|
+
const refreshed = await this.resolve();
|
|
513
|
+
if (refreshed.id !== cart.id || refreshed.status !== "active") throw error;
|
|
514
|
+
cart = refreshed;
|
|
515
|
+
response = await operation(cart);
|
|
516
|
+
}
|
|
517
|
+
return this.write(response.cart);
|
|
518
|
+
}
|
|
519
|
+
save(cart, items, discountCode) {
|
|
520
|
+
return this.client.post(`/carts/${cart.id}`, {
|
|
521
|
+
items: commerceItems(items),
|
|
522
|
+
version: cart.version,
|
|
523
|
+
discountCode
|
|
524
|
+
}, this.options());
|
|
525
|
+
}
|
|
526
|
+
quote(cart, code) {
|
|
527
|
+
if (!cart.items.length) throw new Error("Cannot check a discount on an empty cart");
|
|
528
|
+
return this.client.post("/discounts/check", {
|
|
529
|
+
code,
|
|
530
|
+
items: commerceItems(cart.items)
|
|
531
|
+
}, { access: "public" });
|
|
348
532
|
}
|
|
349
533
|
get() {
|
|
350
|
-
return
|
|
534
|
+
return this.enqueue(async () => {
|
|
535
|
+
let cart = await this.resolve();
|
|
536
|
+
let discount = null;
|
|
537
|
+
if (cart.discountCode) try {
|
|
538
|
+
discount = discountFromQuote(await this.quote(cart, cart.discountCode));
|
|
539
|
+
} catch (error) {
|
|
540
|
+
if (!(error instanceof CaldikHttpError) || ![
|
|
541
|
+
400,
|
|
542
|
+
404,
|
|
543
|
+
422
|
|
544
|
+
].includes(error.status)) throw error;
|
|
545
|
+
cart = (await this.save(cart, cart.items, null)).cart;
|
|
546
|
+
}
|
|
547
|
+
return this.write(cart, this.cache.reference?.token, discount);
|
|
548
|
+
});
|
|
351
549
|
}
|
|
352
550
|
add(item) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
551
|
+
return this.enqueue(async () => {
|
|
552
|
+
if (!item.productId.trim()) throw new Error("Cart productId is required");
|
|
553
|
+
const normalized = {
|
|
554
|
+
...item,
|
|
555
|
+
productId: item.productId.trim(),
|
|
556
|
+
quantity: quantity(item.quantity)
|
|
557
|
+
};
|
|
558
|
+
return this.mutate((cart) => this.client.post(`/carts/${cart.id}/items`, {
|
|
559
|
+
item: normalized,
|
|
560
|
+
version: cart.version
|
|
561
|
+
}, this.options()));
|
|
360
562
|
});
|
|
361
|
-
const existing = state.items.find((entry) => entry.id === id);
|
|
362
|
-
const addedQuantity = quantity(item.quantity);
|
|
363
|
-
if (existing) existing.quantity = quantity(existing.quantity + addedQuantity);
|
|
364
|
-
else state.items.push({
|
|
365
|
-
id,
|
|
366
|
-
productId,
|
|
367
|
-
...productVariantId ? { productVariantId } : {},
|
|
368
|
-
quantity: addedQuantity
|
|
369
|
-
});
|
|
370
|
-
state.discount = null;
|
|
371
|
-
return this.write(state);
|
|
372
563
|
}
|
|
373
564
|
updateQuantity(itemId, nextQuantity) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
565
|
+
return this.enqueue(async () => {
|
|
566
|
+
const normalized = quantity(nextQuantity, true);
|
|
567
|
+
return this.mutate((cart) => {
|
|
568
|
+
if (!cart.items.some((item) => item.id === itemId)) throw new Error("Cart item not found");
|
|
569
|
+
const items = cart.items.map((item) => item.id === itemId ? {
|
|
570
|
+
...item,
|
|
571
|
+
quantity: normalized
|
|
572
|
+
} : item).filter((item) => item.quantity > 0);
|
|
573
|
+
return this.save(cart, items, null);
|
|
574
|
+
});
|
|
575
|
+
});
|
|
382
576
|
}
|
|
383
577
|
remove(itemId) {
|
|
384
|
-
|
|
385
|
-
const items = state.items.filter((item) => item.id !== itemId);
|
|
386
|
-
if (items.length === state.items.length) throw new Error("Cart item not found");
|
|
387
|
-
return this.write({
|
|
388
|
-
items,
|
|
389
|
-
discount: null
|
|
390
|
-
});
|
|
578
|
+
return this.updateQuantity(itemId, 0);
|
|
391
579
|
}
|
|
392
580
|
clear() {
|
|
393
|
-
return this.
|
|
394
|
-
|
|
395
|
-
|
|
581
|
+
return this.enqueue(() => this.mutate((cart) => this.save(cart, [], null), false));
|
|
582
|
+
}
|
|
583
|
+
checkDiscount(code) {
|
|
584
|
+
return this.enqueue(async () => this.quote(await this.resolve(), code));
|
|
585
|
+
}
|
|
586
|
+
applyDiscount(code) {
|
|
587
|
+
return this.enqueue(async () => {
|
|
588
|
+
let quote;
|
|
589
|
+
const snapshot = await this.mutate(async (cart) => {
|
|
590
|
+
quote = await this.quote(cart, code);
|
|
591
|
+
return this.save(cart, cart.items, quote.discount.code);
|
|
592
|
+
});
|
|
593
|
+
snapshot.discount = discountFromQuote(quote);
|
|
594
|
+
this.cache.snapshot = cloneSnapshot(snapshot);
|
|
595
|
+
this.persistCache();
|
|
596
|
+
return snapshot;
|
|
396
597
|
});
|
|
397
598
|
}
|
|
398
|
-
commerceItems() {
|
|
399
|
-
return this.get().items.map(({ productId, productVariantId, quantity }) => ({
|
|
400
|
-
productId,
|
|
401
|
-
...productVariantId ? { productVariantId } : {},
|
|
402
|
-
quantity
|
|
403
|
-
}));
|
|
404
|
-
}
|
|
405
|
-
async checkDiscount(code) {
|
|
406
|
-
const items = this.commerceItems();
|
|
407
|
-
if (items.length === 0) throw new Error("Cannot check a discount on an empty cart");
|
|
408
|
-
return this.client.post("/discounts/check", {
|
|
409
|
-
code,
|
|
410
|
-
items
|
|
411
|
-
}, { access: "public" });
|
|
412
|
-
}
|
|
413
|
-
async applyDiscount(code) {
|
|
414
|
-
const quote = await this.checkDiscount(code);
|
|
415
|
-
const state = this.get();
|
|
416
|
-
state.discount = {
|
|
417
|
-
...quote.discount,
|
|
418
|
-
subtotal: quote.subtotal,
|
|
419
|
-
discountAmount: quote.discountAmount,
|
|
420
|
-
total: quote.total,
|
|
421
|
-
currency: quote.currency
|
|
422
|
-
};
|
|
423
|
-
return this.write(state);
|
|
424
|
-
}
|
|
425
599
|
removeDiscount() {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return response;
|
|
600
|
+
return this.enqueue(() => this.mutate((cart) => this.save(cart, cart.items, null)));
|
|
601
|
+
}
|
|
602
|
+
checkout(input = {}) {
|
|
603
|
+
return this.enqueue(async () => {
|
|
604
|
+
const cart = await this.resolve(true);
|
|
605
|
+
if (!cart.items.length) throw new Error("Cannot checkout an empty cart");
|
|
606
|
+
const response = await this.client.post(`/carts/${cart.id}/checkout`, {
|
|
607
|
+
...input,
|
|
608
|
+
version: cart.version
|
|
609
|
+
}, this.options());
|
|
610
|
+
this.reset();
|
|
611
|
+
return response;
|
|
612
|
+
});
|
|
440
613
|
}
|
|
441
614
|
};
|
|
442
615
|
//#endregion
|
|
@@ -497,7 +670,9 @@ var CaldikClient = class {
|
|
|
497
670
|
const client = new CaldikHttpClient({
|
|
498
671
|
apiKey: options.apiKey,
|
|
499
672
|
apiUrl: options.apiUrl,
|
|
500
|
-
storeId: options.storeId
|
|
673
|
+
storeId: options.storeId,
|
|
674
|
+
request: options.request,
|
|
675
|
+
onSetCookie: options.onSetCookie
|
|
501
676
|
});
|
|
502
677
|
this.categories = new CategoriesApi(client);
|
|
503
678
|
this.products = new ProductsApi(client);
|