@caldik/client 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/dist/index.d.mts +118 -20
- package/dist/index.mjs +189 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,3 +22,60 @@ const caldik = new CaldikClient({
|
|
|
22
22
|
apiKey: process.env.CALDIK_PRIVATE_API_KEY,
|
|
23
23
|
})
|
|
24
24
|
```
|
|
25
|
+
|
|
26
|
+
## Cart and discounts
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
const cart = caldik.cart.add({
|
|
31
|
+
productId: "PRODUCT_...",
|
|
32
|
+
productVariantId: "PRODUCT_VARIANT_...",
|
|
33
|
+
quantity: 1,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
caldik.cart.updateQuantity(cart.items[0].id, 3)
|
|
37
|
+
caldik.cart.remove(cart.items[0].id)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
await caldik.cart.applyDiscount("SAVE10")
|
|
42
|
+
|
|
43
|
+
const result = await caldik.cart.checkout({
|
|
44
|
+
paymentMethod: "stripe",
|
|
45
|
+
items: [{ productId, productVariantId, quantity: 1 }],
|
|
46
|
+
termsAccepted: acceptedTermsCheckbox,
|
|
47
|
+
successUrl: "https://shop.example/success",
|
|
48
|
+
cancelUrl: "https://shop.example/cart",
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Use `caldik.discounts.check({ code, items })` when a cart should be managed by
|
|
53
|
+
the application instead of the SDK.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Customer Logins
|
|
57
|
+
|
|
58
|
+
Magic Code
|
|
59
|
+
```ts
|
|
60
|
+
await caldik.customer.requestLogin("customer@example.com")
|
|
61
|
+
await caldik.customer.verifyLogin(code)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Username / Email Password ( if password login is enabled )
|
|
65
|
+
```ts
|
|
66
|
+
await caldik.customer.login({ username: "customer", password })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
if you are logged in using magic code you can just do
|
|
70
|
+
- this to enroll the customers account into username / email password login ( password login needs to be enabled in the dashboard )
|
|
71
|
+
```ts
|
|
72
|
+
await caldik.customer.setPassword({ username: "customer", password })
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Payment methods and Settings
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const { settings: loginSettings } = await caldik.customer.settings.get()
|
|
79
|
+
const { settings: checkoutSettings } = await caldik.checkout.settings.get()
|
|
80
|
+
const { paymentMethods } = await caldik.checkout.paymentmethods.list()
|
|
81
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -99,6 +99,7 @@ interface Product {
|
|
|
99
99
|
interface ProductVariant {
|
|
100
100
|
id: string;
|
|
101
101
|
name: string;
|
|
102
|
+
position: number;
|
|
102
103
|
price: string;
|
|
103
104
|
compareAtPrice: string | null;
|
|
104
105
|
}
|
|
@@ -146,8 +147,10 @@ type CommerceItem = ManualCommerceItem | ProductCommerceItem;
|
|
|
146
147
|
interface CreateOrderInput {
|
|
147
148
|
customerId?: string;
|
|
148
149
|
email?: string;
|
|
150
|
+
termsAccepted?: boolean;
|
|
149
151
|
paymentMethod: CheckoutPaymentProviderId;
|
|
150
152
|
items: CommerceItem[];
|
|
153
|
+
discountCode?: string;
|
|
151
154
|
successUrl?: string;
|
|
152
155
|
cancelUrl?: string;
|
|
153
156
|
}
|
|
@@ -158,7 +161,13 @@ interface StorefrontOrder {
|
|
|
158
161
|
customerId: string | null;
|
|
159
162
|
paymentStatus: string;
|
|
160
163
|
fulfillmentStatus: string;
|
|
164
|
+
subtotal: string;
|
|
161
165
|
amount: string;
|
|
166
|
+
discount: {
|
|
167
|
+
code: string;
|
|
168
|
+
percentage: string;
|
|
169
|
+
amount: string;
|
|
170
|
+
} | null;
|
|
162
171
|
currency: string;
|
|
163
172
|
}
|
|
164
173
|
interface CheckoutPayment {
|
|
@@ -202,18 +211,6 @@ interface SubscriptionResponse {
|
|
|
202
211
|
checkoutSessionId: string;
|
|
203
212
|
};
|
|
204
213
|
}
|
|
205
|
-
interface StoreWebhookEventDefinition {
|
|
206
|
-
name: StoreWebhookEventName;
|
|
207
|
-
resource: string;
|
|
208
|
-
action: string;
|
|
209
|
-
description: string;
|
|
210
|
-
}
|
|
211
|
-
interface StoreWebhookEventsResponse {
|
|
212
|
-
success: boolean;
|
|
213
|
-
apiVersion: "v1";
|
|
214
|
-
catalogVersion: string;
|
|
215
|
-
events: StoreWebhookEventDefinition[];
|
|
216
|
-
}
|
|
217
214
|
interface StoreWebhookEvent<TObject extends Record<string, unknown> = Record<string, unknown>> {
|
|
218
215
|
id: string;
|
|
219
216
|
type: StoreWebhookEventName;
|
|
@@ -234,10 +231,43 @@ interface CustomerLoginVerifyResponse {
|
|
|
234
231
|
id: string;
|
|
235
232
|
shortId: string;
|
|
236
233
|
displayId: string;
|
|
237
|
-
email: string;
|
|
234
|
+
email: string | null;
|
|
238
235
|
status: string;
|
|
239
236
|
};
|
|
240
237
|
}
|
|
238
|
+
interface CustomerPasswordInput {
|
|
239
|
+
username: string;
|
|
240
|
+
password: string;
|
|
241
|
+
}
|
|
242
|
+
interface CustomerLoginSettings {
|
|
243
|
+
passwordEnabled: boolean;
|
|
244
|
+
}
|
|
245
|
+
interface CustomerLoginSettingsResponse {
|
|
246
|
+
success: boolean;
|
|
247
|
+
settings: CustomerLoginSettings;
|
|
248
|
+
}
|
|
249
|
+
interface CheckoutSettings {
|
|
250
|
+
requireEmail: boolean;
|
|
251
|
+
requireTermsAcceptance: boolean;
|
|
252
|
+
}
|
|
253
|
+
interface CheckoutSettingsResponse {
|
|
254
|
+
success: boolean;
|
|
255
|
+
settings: CheckoutSettings;
|
|
256
|
+
}
|
|
257
|
+
interface CheckoutPaymentMethod {
|
|
258
|
+
id: CheckoutPaymentProviderId;
|
|
259
|
+
label: string;
|
|
260
|
+
description: string;
|
|
261
|
+
checkout: {
|
|
262
|
+
kind: "internal" | "redirect";
|
|
263
|
+
requiresCustomerEmail: boolean;
|
|
264
|
+
};
|
|
265
|
+
requiresCustomerLogin: boolean;
|
|
266
|
+
}
|
|
267
|
+
interface CheckoutPaymentMethodsResponse {
|
|
268
|
+
success: boolean;
|
|
269
|
+
paymentMethods: CheckoutPaymentMethod[];
|
|
270
|
+
}
|
|
241
271
|
//#endregion
|
|
242
272
|
//#region src/internal/types.d.ts
|
|
243
273
|
interface RequestOptions {
|
|
@@ -257,6 +287,7 @@ declare class CaldikHttpClient {
|
|
|
257
287
|
private readonly apiUrl;
|
|
258
288
|
private readonly storeId?;
|
|
259
289
|
constructor(options?: HttpClientOptions);
|
|
290
|
+
storeContextId(): string | null;
|
|
260
291
|
private baseUrl;
|
|
261
292
|
private request;
|
|
262
293
|
get<T>(path: string, params?: Record<string, string | number>, options?: RequestOptions): Promise<T>;
|
|
@@ -276,7 +307,7 @@ declare class ProductsApi {
|
|
|
276
307
|
private client;
|
|
277
308
|
constructor(client: CaldikHttpClient);
|
|
278
309
|
list(): Promise<ProductsResponse>;
|
|
279
|
-
get(
|
|
310
|
+
get(productIdOrSlug: string): Promise<ProductResponse>;
|
|
280
311
|
}
|
|
281
312
|
//#endregion
|
|
282
313
|
//#region src/reviews.d.ts
|
|
@@ -296,6 +327,12 @@ declare class StoreApi {
|
|
|
296
327
|
//#region src/checkout.d.ts
|
|
297
328
|
declare class CheckoutApi {
|
|
298
329
|
private client;
|
|
330
|
+
readonly paymentmethods: {
|
|
331
|
+
list: () => Promise<CheckoutPaymentMethodsResponse>;
|
|
332
|
+
};
|
|
333
|
+
readonly settings: {
|
|
334
|
+
get: () => Promise<CheckoutSettingsResponse>;
|
|
335
|
+
};
|
|
299
336
|
constructor(client: CaldikHttpClient);
|
|
300
337
|
create(input: CreateOrderInput): Promise<OrderResponse>;
|
|
301
338
|
payWithBalance(orderId: string): Promise<OrderResponse>;
|
|
@@ -304,7 +341,13 @@ declare class CheckoutApi {
|
|
|
304
341
|
//#region src/customer.d.ts
|
|
305
342
|
declare class CustomerApi {
|
|
306
343
|
private client;
|
|
344
|
+
readonly settings: {
|
|
345
|
+
get: () => Promise<CustomerLoginSettingsResponse>;
|
|
346
|
+
};
|
|
307
347
|
constructor(client: CaldikHttpClient);
|
|
348
|
+
login(input: CustomerPasswordInput): Promise<CustomerLoginVerifyResponse>;
|
|
349
|
+
/** Set or reset credentials after signing in with an email code. Requires a customer session. */
|
|
350
|
+
setPassword(input: CustomerPasswordInput): Promise<CustomerLoginVerifyResponse>;
|
|
308
351
|
requestLogin(email: string): Promise<CustomerLoginResponse>;
|
|
309
352
|
verifyLogin(code: string): Promise<CustomerLoginVerifyResponse>;
|
|
310
353
|
}
|
|
@@ -316,12 +359,66 @@ declare class SubscriptionsApi {
|
|
|
316
359
|
create(input: CreateSubscriptionInput): Promise<SubscriptionResponse>;
|
|
317
360
|
}
|
|
318
361
|
//#endregion
|
|
319
|
-
//#region src/
|
|
320
|
-
|
|
362
|
+
//#region src/discounts.d.ts
|
|
363
|
+
interface CheckDiscountInput {
|
|
364
|
+
code: string;
|
|
365
|
+
items: CommerceItem[];
|
|
366
|
+
}
|
|
367
|
+
interface AppliedDiscount {
|
|
368
|
+
code: string;
|
|
369
|
+
percentage: string;
|
|
370
|
+
}
|
|
371
|
+
interface DiscountQuoteResponse {
|
|
372
|
+
success: boolean;
|
|
373
|
+
discount: AppliedDiscount;
|
|
374
|
+
subtotal: string;
|
|
375
|
+
discountAmount: string;
|
|
376
|
+
total: string;
|
|
377
|
+
currency: string;
|
|
378
|
+
}
|
|
379
|
+
declare class DiscountsApi {
|
|
380
|
+
private client;
|
|
381
|
+
constructor(client: CaldikHttpClient);
|
|
382
|
+
check(input: CheckDiscountInput): Promise<DiscountQuoteResponse>;
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/cart.d.ts
|
|
386
|
+
interface CartItem {
|
|
387
|
+
id: string;
|
|
388
|
+
productId: string;
|
|
389
|
+
productVariantId?: string;
|
|
390
|
+
quantity: number;
|
|
391
|
+
}
|
|
392
|
+
interface CartDiscount {
|
|
393
|
+
code: string;
|
|
394
|
+
percentage: string;
|
|
395
|
+
subtotal: string;
|
|
396
|
+
discountAmount: string;
|
|
397
|
+
total: string;
|
|
398
|
+
currency: string;
|
|
399
|
+
}
|
|
400
|
+
interface CartSnapshot {
|
|
401
|
+
items: CartItem[];
|
|
402
|
+
discount: CartDiscount | null;
|
|
403
|
+
}
|
|
404
|
+
type CartCheckoutInput = Omit<CreateOrderInput, "items" | "discountCode">;
|
|
405
|
+
declare class CartApi {
|
|
321
406
|
private client;
|
|
407
|
+
private memory;
|
|
322
408
|
constructor(client: CaldikHttpClient);
|
|
323
|
-
|
|
324
|
-
|
|
409
|
+
private storageKey;
|
|
410
|
+
private read;
|
|
411
|
+
private write;
|
|
412
|
+
get(): CartSnapshot;
|
|
413
|
+
add(item: ProductCommerceItem): CartSnapshot;
|
|
414
|
+
updateQuantity(itemId: string, nextQuantity: number): CartSnapshot;
|
|
415
|
+
remove(itemId: string): CartSnapshot;
|
|
416
|
+
clear(): CartSnapshot;
|
|
417
|
+
private commerceItems;
|
|
418
|
+
checkDiscount(code: string): Promise<DiscountQuoteResponse>;
|
|
419
|
+
applyDiscount(code: string): Promise<CartSnapshot>;
|
|
420
|
+
removeDiscount(): CartSnapshot;
|
|
421
|
+
checkout(input: CartCheckoutInput): Promise<OrderResponse>;
|
|
325
422
|
}
|
|
326
423
|
//#endregion
|
|
327
424
|
//#region src/index.d.ts
|
|
@@ -340,8 +437,9 @@ declare class CaldikClient {
|
|
|
340
437
|
readonly checkout: CheckoutApi;
|
|
341
438
|
readonly customer: CustomerApi;
|
|
342
439
|
readonly subscriptions: SubscriptionsApi;
|
|
343
|
-
readonly
|
|
440
|
+
readonly discounts: DiscountsApi;
|
|
441
|
+
readonly cart: CartApi;
|
|
344
442
|
constructor(options?: CaldikClientOptions);
|
|
345
443
|
}
|
|
346
444
|
//#endregion
|
|
347
|
-
export { CaldikClient, CaldikClientOptions, CategoriesResponse, Category, CategoryDetails, CategoryMetadata, CategoryProduct, CategoryResponse, CheckoutPayment, CheckoutPaymentProviderId, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerLoginResponse, CustomerLoginVerifyResponse, ManualCommerceItem, OrderResponse, PaymentProviderId, Product, ProductCommerceItem, ProductCustomField, ProductCustomFieldInputType, ProductCustomFieldOption, ProductMetadata, ProductResponse, ProductTag, ProductVariant, ProductsResponse, Review, ReviewsResponse, Store, StoreResponse, StoreWebhookEvent,
|
|
445
|
+
export { AppliedDiscount, CaldikClient, CaldikClientOptions, CartApi, CartCheckoutInput, CartDiscount, CartItem, CartSnapshot, CategoriesResponse, Category, CategoryDetails, CategoryMetadata, CategoryProduct, CategoryResponse, CheckDiscountInput, CheckoutPayment, CheckoutPaymentMethod, CheckoutPaymentMethodsResponse, CheckoutPaymentProviderId, CheckoutSettings, CheckoutSettingsResponse, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerLoginResponse, CustomerLoginSettings, CustomerLoginSettingsResponse, CustomerLoginVerifyResponse, CustomerPasswordInput, 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 };
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,6 @@ function firstValue(...values) {
|
|
|
8
8
|
function importMetaEnvironment() {
|
|
9
9
|
return import.meta.env;
|
|
10
10
|
}
|
|
11
|
-
/** Public context exposed by Next/Vinext, Vite, or Astro during `caldik dev`. */
|
|
12
11
|
function browserBuildStoreId() {
|
|
13
12
|
const environment = importMetaEnvironment();
|
|
14
13
|
return firstValue(typeof process === "undefined" ? void 0 : process.env.NEXT_PUBLIC_CALDIK_STORE_ID, environment?.VITE_CALDIK_STORE_ID, environment?.PUBLIC_CALDIK_STORE_ID);
|
|
@@ -58,6 +57,9 @@ var CaldikHttpClient = class {
|
|
|
58
57
|
if (isBrowserRuntime() && this.apiKey) throw new Error("Caldik private API keys cannot be used in browser code");
|
|
59
58
|
this.storeId = configuredStoreId || (isBrowserRuntime() ? browserRuntimeStoreId() || void 0 : void 0);
|
|
60
59
|
}
|
|
60
|
+
storeContextId() {
|
|
61
|
+
return this.storeId || boundRuntimeStoreId();
|
|
62
|
+
}
|
|
61
63
|
baseUrl() {
|
|
62
64
|
if (isBrowserRuntime()) {
|
|
63
65
|
const storeId = this.storeId;
|
|
@@ -125,8 +127,8 @@ var ProductsApi = class {
|
|
|
125
127
|
list() {
|
|
126
128
|
return this.client.get("/products", void 0, { access: "public" });
|
|
127
129
|
}
|
|
128
|
-
get(
|
|
129
|
-
return this.client.get(`/products/${
|
|
130
|
+
get(productIdOrSlug) {
|
|
131
|
+
return this.client.get(`/products/${encodeURIComponent(productIdOrSlug)}`, void 0, { access: "public" });
|
|
130
132
|
}
|
|
131
133
|
};
|
|
132
134
|
//#endregion
|
|
@@ -155,8 +157,12 @@ var StoreApi = class {
|
|
|
155
157
|
//#region src/checkout.ts
|
|
156
158
|
var CheckoutApi = class {
|
|
157
159
|
client;
|
|
160
|
+
paymentmethods;
|
|
161
|
+
settings;
|
|
158
162
|
constructor(client) {
|
|
159
163
|
this.client = client;
|
|
164
|
+
this.paymentmethods = { list: () => this.client.get("/checkouts/payment-methods", void 0, { access: "public" }) };
|
|
165
|
+
this.settings = { get: () => this.client.get("/checkouts/settings", void 0, { access: "public" }) };
|
|
160
166
|
}
|
|
161
167
|
create(input) {
|
|
162
168
|
return this.client.post("/checkouts", input, { access: "public" });
|
|
@@ -169,8 +175,17 @@ var CheckoutApi = class {
|
|
|
169
175
|
//#region src/customer.ts
|
|
170
176
|
var CustomerApi = class {
|
|
171
177
|
client;
|
|
178
|
+
settings;
|
|
172
179
|
constructor(client) {
|
|
173
180
|
this.client = client;
|
|
181
|
+
this.settings = { get: () => this.client.get("/customers/settings", void 0, { access: "public" }) };
|
|
182
|
+
}
|
|
183
|
+
login(input) {
|
|
184
|
+
return this.client.post("/customers/login/password", input, { access: "public" });
|
|
185
|
+
}
|
|
186
|
+
/** Set or reset credentials after signing in with an email code. Requires a customer session. */
|
|
187
|
+
setPassword(input) {
|
|
188
|
+
return this.client.post("/customers/password", input, { access: "public" });
|
|
174
189
|
}
|
|
175
190
|
requestLogin(email) {
|
|
176
191
|
return this.client.post("/customers/login", { email }, { access: "public" });
|
|
@@ -191,15 +206,176 @@ var SubscriptionsApi = class {
|
|
|
191
206
|
}
|
|
192
207
|
};
|
|
193
208
|
//#endregion
|
|
194
|
-
//#region src/
|
|
195
|
-
var
|
|
209
|
+
//#region src/discounts.ts
|
|
210
|
+
var DiscountsApi = class {
|
|
211
|
+
client;
|
|
212
|
+
constructor(client) {
|
|
213
|
+
this.client = client;
|
|
214
|
+
}
|
|
215
|
+
check(input) {
|
|
216
|
+
return this.client.post("/discounts/check", input, { access: "public" });
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/cart.ts
|
|
221
|
+
const CART_VERSION = 1;
|
|
222
|
+
const MAX_QUANTITY = 999999;
|
|
223
|
+
function cartItemId(item) {
|
|
224
|
+
return item.productVariantId ? `${item.productId}:${item.productVariantId}` : item.productId;
|
|
225
|
+
}
|
|
226
|
+
function quantity(value, allowZero = false) {
|
|
227
|
+
const normalized = value ?? 1;
|
|
228
|
+
const minimum = allowZero ? 0 : 1;
|
|
229
|
+
if (!Number.isInteger(normalized) || normalized < minimum || normalized > MAX_QUANTITY) throw new Error(`Cart quantity must be an integer between ${minimum} and ${MAX_QUANTITY}`);
|
|
230
|
+
return normalized;
|
|
231
|
+
}
|
|
232
|
+
function cloneSnapshot(state) {
|
|
233
|
+
return {
|
|
234
|
+
items: state.items.map((item) => ({ ...item })),
|
|
235
|
+
discount: state.discount ? { ...state.discount } : null
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function isCartItem(value) {
|
|
239
|
+
if (!value || typeof value !== "object") return false;
|
|
240
|
+
const item = value;
|
|
241
|
+
return typeof item.id === "string" && typeof item.productId === "string" && (item.productVariantId === void 0 || typeof item.productVariantId === "string") && typeof item.quantity === "number" && Number.isInteger(item.quantity) && item.quantity > 0 && item.quantity <= MAX_QUANTITY;
|
|
242
|
+
}
|
|
243
|
+
function isCartDiscount(value) {
|
|
244
|
+
if (!value || typeof value !== "object") return false;
|
|
245
|
+
const discount = value;
|
|
246
|
+
return typeof discount.code === "string" && typeof discount.percentage === "string" && typeof discount.subtotal === "string" && typeof discount.discountAmount === "string" && typeof discount.total === "string" && typeof discount.currency === "string";
|
|
247
|
+
}
|
|
248
|
+
var CartApi = class {
|
|
196
249
|
client;
|
|
250
|
+
memory = {
|
|
251
|
+
version: CART_VERSION,
|
|
252
|
+
items: [],
|
|
253
|
+
discount: null
|
|
254
|
+
};
|
|
197
255
|
constructor(client) {
|
|
198
256
|
this.client = client;
|
|
199
257
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return
|
|
258
|
+
storageKey() {
|
|
259
|
+
const storeId = this.client.storeContextId();
|
|
260
|
+
return storeId ? `caldik:cart:${storeId}` : null;
|
|
261
|
+
}
|
|
262
|
+
read() {
|
|
263
|
+
const key = this.storageKey();
|
|
264
|
+
if (key && typeof localStorage !== "undefined") try {
|
|
265
|
+
const value = localStorage.getItem(key);
|
|
266
|
+
if (value) {
|
|
267
|
+
const parsed = JSON.parse(value);
|
|
268
|
+
if (parsed.version === CART_VERSION && Array.isArray(parsed.items) && parsed.items.every(isCartItem)) this.memory = {
|
|
269
|
+
version: CART_VERSION,
|
|
270
|
+
items: parsed.items,
|
|
271
|
+
discount: isCartDiscount(parsed.discount) ? parsed.discount : null
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
} catch {}
|
|
275
|
+
return this.memory;
|
|
276
|
+
}
|
|
277
|
+
write(state) {
|
|
278
|
+
this.memory = {
|
|
279
|
+
version: CART_VERSION,
|
|
280
|
+
...cloneSnapshot(state)
|
|
281
|
+
};
|
|
282
|
+
const key = this.storageKey();
|
|
283
|
+
if (key && typeof localStorage !== "undefined") try {
|
|
284
|
+
localStorage.setItem(key, JSON.stringify(this.memory));
|
|
285
|
+
} catch {}
|
|
286
|
+
return this.get();
|
|
287
|
+
}
|
|
288
|
+
get() {
|
|
289
|
+
return cloneSnapshot(this.read());
|
|
290
|
+
}
|
|
291
|
+
add(item) {
|
|
292
|
+
const productId = item.productId.trim();
|
|
293
|
+
const productVariantId = item.productVariantId?.trim() || "";
|
|
294
|
+
if (!productId) throw new Error("Cart productId is required");
|
|
295
|
+
const state = this.get();
|
|
296
|
+
const id = cartItemId({
|
|
297
|
+
productId,
|
|
298
|
+
productVariantId
|
|
299
|
+
});
|
|
300
|
+
const existing = state.items.find((entry) => entry.id === id);
|
|
301
|
+
const addedQuantity = quantity(item.quantity);
|
|
302
|
+
if (existing) existing.quantity = quantity(existing.quantity + addedQuantity);
|
|
303
|
+
else state.items.push({
|
|
304
|
+
id,
|
|
305
|
+
productId,
|
|
306
|
+
...productVariantId ? { productVariantId } : {},
|
|
307
|
+
quantity: addedQuantity
|
|
308
|
+
});
|
|
309
|
+
state.discount = null;
|
|
310
|
+
return this.write(state);
|
|
311
|
+
}
|
|
312
|
+
updateQuantity(itemId, nextQuantity) {
|
|
313
|
+
const state = this.get();
|
|
314
|
+
const normalized = quantity(nextQuantity, true);
|
|
315
|
+
const index = state.items.findIndex((item) => item.id === itemId);
|
|
316
|
+
if (index === -1) throw new Error("Cart item not found");
|
|
317
|
+
if (normalized === 0) state.items.splice(index, 1);
|
|
318
|
+
else state.items[index].quantity = normalized;
|
|
319
|
+
state.discount = null;
|
|
320
|
+
return this.write(state);
|
|
321
|
+
}
|
|
322
|
+
remove(itemId) {
|
|
323
|
+
const state = this.get();
|
|
324
|
+
const items = state.items.filter((item) => item.id !== itemId);
|
|
325
|
+
if (items.length === state.items.length) throw new Error("Cart item not found");
|
|
326
|
+
return this.write({
|
|
327
|
+
items,
|
|
328
|
+
discount: null
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
clear() {
|
|
332
|
+
return this.write({
|
|
333
|
+
items: [],
|
|
334
|
+
discount: null
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
commerceItems() {
|
|
338
|
+
return this.get().items.map(({ productId, productVariantId, quantity }) => ({
|
|
339
|
+
productId,
|
|
340
|
+
...productVariantId ? { productVariantId } : {},
|
|
341
|
+
quantity
|
|
342
|
+
}));
|
|
343
|
+
}
|
|
344
|
+
async checkDiscount(code) {
|
|
345
|
+
const items = this.commerceItems();
|
|
346
|
+
if (items.length === 0) throw new Error("Cannot check a discount on an empty cart");
|
|
347
|
+
return this.client.post("/discounts/check", {
|
|
348
|
+
code,
|
|
349
|
+
items
|
|
350
|
+
}, { access: "public" });
|
|
351
|
+
}
|
|
352
|
+
async applyDiscount(code) {
|
|
353
|
+
const quote = await this.checkDiscount(code);
|
|
354
|
+
const state = this.get();
|
|
355
|
+
state.discount = {
|
|
356
|
+
...quote.discount,
|
|
357
|
+
subtotal: quote.subtotal,
|
|
358
|
+
discountAmount: quote.discountAmount,
|
|
359
|
+
total: quote.total,
|
|
360
|
+
currency: quote.currency
|
|
361
|
+
};
|
|
362
|
+
return this.write(state);
|
|
363
|
+
}
|
|
364
|
+
removeDiscount() {
|
|
365
|
+
const state = this.get();
|
|
366
|
+
state.discount = null;
|
|
367
|
+
return this.write(state);
|
|
368
|
+
}
|
|
369
|
+
async checkout(input) {
|
|
370
|
+
const state = this.get();
|
|
371
|
+
if (state.items.length === 0) throw new Error("Cannot checkout an empty cart");
|
|
372
|
+
const response = await this.client.post("/checkouts", {
|
|
373
|
+
...input,
|
|
374
|
+
items: this.commerceItems(),
|
|
375
|
+
...state.discount ? { discountCode: state.discount.code } : {}
|
|
376
|
+
}, { access: "public" });
|
|
377
|
+
this.clear();
|
|
378
|
+
return response;
|
|
203
379
|
}
|
|
204
380
|
};
|
|
205
381
|
//#endregion
|
|
@@ -254,7 +430,8 @@ var CaldikClient = class {
|
|
|
254
430
|
checkout;
|
|
255
431
|
customer;
|
|
256
432
|
subscriptions;
|
|
257
|
-
|
|
433
|
+
discounts;
|
|
434
|
+
cart;
|
|
258
435
|
constructor(options = {}) {
|
|
259
436
|
const client = new CaldikHttpClient({
|
|
260
437
|
apiKey: options.apiKey,
|
|
@@ -268,8 +445,9 @@ var CaldikClient = class {
|
|
|
268
445
|
this.checkout = new CheckoutApi(client);
|
|
269
446
|
this.customer = new CustomerApi(client);
|
|
270
447
|
this.subscriptions = new SubscriptionsApi(client);
|
|
271
|
-
this.
|
|
448
|
+
this.discounts = new DiscountsApi(client);
|
|
449
|
+
this.cart = new CartApi(client);
|
|
272
450
|
}
|
|
273
451
|
};
|
|
274
452
|
//#endregion
|
|
275
|
-
export { CaldikClient, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|
|
453
|
+
export { CaldikClient, CartApi, DiscountsApi, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|