@caldik/client 0.0.8 → 0.0.9
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 +28 -0
- package/dist/index.d.mts +69 -18
- package/dist/index.mjs +174 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,3 +22,31 @@ 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
|
+
successUrl: "https://shop.example/success",
|
|
46
|
+
cancelUrl: "https://shop.example/cart",
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Use `caldik.discounts.check({ code, items })` when a cart should be managed by
|
|
51
|
+
the application instead of the SDK.
|
|
52
|
+
|
package/dist/index.d.mts
CHANGED
|
@@ -148,6 +148,7 @@ interface CreateOrderInput {
|
|
|
148
148
|
email?: string;
|
|
149
149
|
paymentMethod: CheckoutPaymentProviderId;
|
|
150
150
|
items: CommerceItem[];
|
|
151
|
+
discountCode?: string;
|
|
151
152
|
successUrl?: string;
|
|
152
153
|
cancelUrl?: string;
|
|
153
154
|
}
|
|
@@ -158,7 +159,13 @@ interface StorefrontOrder {
|
|
|
158
159
|
customerId: string | null;
|
|
159
160
|
paymentStatus: string;
|
|
160
161
|
fulfillmentStatus: string;
|
|
162
|
+
subtotal: string;
|
|
161
163
|
amount: string;
|
|
164
|
+
discount: {
|
|
165
|
+
code: string;
|
|
166
|
+
percentage: string;
|
|
167
|
+
amount: string;
|
|
168
|
+
} | null;
|
|
162
169
|
currency: string;
|
|
163
170
|
}
|
|
164
171
|
interface CheckoutPayment {
|
|
@@ -202,18 +209,6 @@ interface SubscriptionResponse {
|
|
|
202
209
|
checkoutSessionId: string;
|
|
203
210
|
};
|
|
204
211
|
}
|
|
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
212
|
interface StoreWebhookEvent<TObject extends Record<string, unknown> = Record<string, unknown>> {
|
|
218
213
|
id: string;
|
|
219
214
|
type: StoreWebhookEventName;
|
|
@@ -257,6 +252,7 @@ declare class CaldikHttpClient {
|
|
|
257
252
|
private readonly apiUrl;
|
|
258
253
|
private readonly storeId?;
|
|
259
254
|
constructor(options?: HttpClientOptions);
|
|
255
|
+
storeContextId(): string | null;
|
|
260
256
|
private baseUrl;
|
|
261
257
|
private request;
|
|
262
258
|
get<T>(path: string, params?: Record<string, string | number>, options?: RequestOptions): Promise<T>;
|
|
@@ -316,12 +312,66 @@ declare class SubscriptionsApi {
|
|
|
316
312
|
create(input: CreateSubscriptionInput): Promise<SubscriptionResponse>;
|
|
317
313
|
}
|
|
318
314
|
//#endregion
|
|
319
|
-
//#region src/
|
|
320
|
-
|
|
315
|
+
//#region src/discounts.d.ts
|
|
316
|
+
interface CheckDiscountInput {
|
|
317
|
+
code: string;
|
|
318
|
+
items: CommerceItem[];
|
|
319
|
+
}
|
|
320
|
+
interface AppliedDiscount {
|
|
321
|
+
code: string;
|
|
322
|
+
percentage: string;
|
|
323
|
+
}
|
|
324
|
+
interface DiscountQuoteResponse {
|
|
325
|
+
success: boolean;
|
|
326
|
+
discount: AppliedDiscount;
|
|
327
|
+
subtotal: string;
|
|
328
|
+
discountAmount: string;
|
|
329
|
+
total: string;
|
|
330
|
+
currency: string;
|
|
331
|
+
}
|
|
332
|
+
declare class DiscountsApi {
|
|
333
|
+
private client;
|
|
334
|
+
constructor(client: CaldikHttpClient);
|
|
335
|
+
check(input: CheckDiscountInput): Promise<DiscountQuoteResponse>;
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/cart.d.ts
|
|
339
|
+
interface CartItem {
|
|
340
|
+
id: string;
|
|
341
|
+
productId: string;
|
|
342
|
+
productVariantId?: string;
|
|
343
|
+
quantity: number;
|
|
344
|
+
}
|
|
345
|
+
interface CartDiscount {
|
|
346
|
+
code: string;
|
|
347
|
+
percentage: string;
|
|
348
|
+
subtotal: string;
|
|
349
|
+
discountAmount: string;
|
|
350
|
+
total: string;
|
|
351
|
+
currency: string;
|
|
352
|
+
}
|
|
353
|
+
interface CartSnapshot {
|
|
354
|
+
items: CartItem[];
|
|
355
|
+
discount: CartDiscount | null;
|
|
356
|
+
}
|
|
357
|
+
type CartCheckoutInput = Omit<CreateOrderInput, "items" | "discountCode">;
|
|
358
|
+
declare class CartApi {
|
|
321
359
|
private client;
|
|
360
|
+
private memory;
|
|
322
361
|
constructor(client: CaldikHttpClient);
|
|
323
|
-
|
|
324
|
-
|
|
362
|
+
private storageKey;
|
|
363
|
+
private read;
|
|
364
|
+
private write;
|
|
365
|
+
get(): CartSnapshot;
|
|
366
|
+
add(item: ProductCommerceItem): CartSnapshot;
|
|
367
|
+
updateQuantity(itemId: string, nextQuantity: number): CartSnapshot;
|
|
368
|
+
remove(itemId: string): CartSnapshot;
|
|
369
|
+
clear(): CartSnapshot;
|
|
370
|
+
private commerceItems;
|
|
371
|
+
checkDiscount(code: string): Promise<DiscountQuoteResponse>;
|
|
372
|
+
applyDiscount(code: string): Promise<CartSnapshot>;
|
|
373
|
+
removeDiscount(): CartSnapshot;
|
|
374
|
+
checkout(input: CartCheckoutInput): Promise<OrderResponse>;
|
|
325
375
|
}
|
|
326
376
|
//#endregion
|
|
327
377
|
//#region src/index.d.ts
|
|
@@ -340,8 +390,9 @@ declare class CaldikClient {
|
|
|
340
390
|
readonly checkout: CheckoutApi;
|
|
341
391
|
readonly customer: CustomerApi;
|
|
342
392
|
readonly subscriptions: SubscriptionsApi;
|
|
343
|
-
readonly
|
|
393
|
+
readonly discounts: DiscountsApi;
|
|
394
|
+
readonly cart: CartApi;
|
|
344
395
|
constructor(options?: CaldikClientOptions);
|
|
345
396
|
}
|
|
346
397
|
//#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,
|
|
398
|
+
export { AppliedDiscount, CaldikClient, CaldikClientOptions, CartApi, CartCheckoutInput, CartDiscount, CartItem, CartSnapshot, CategoriesResponse, Category, CategoryDetails, CategoryMetadata, CategoryProduct, CategoryResponse, CheckDiscountInput, CheckoutPayment, CheckoutPaymentProviderId, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerLoginResponse, CustomerLoginVerifyResponse, 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;
|
|
@@ -191,15 +193,176 @@ var SubscriptionsApi = class {
|
|
|
191
193
|
}
|
|
192
194
|
};
|
|
193
195
|
//#endregion
|
|
194
|
-
//#region src/
|
|
195
|
-
var
|
|
196
|
+
//#region src/discounts.ts
|
|
197
|
+
var DiscountsApi = class {
|
|
196
198
|
client;
|
|
197
199
|
constructor(client) {
|
|
198
200
|
this.client = client;
|
|
199
201
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
202
|
+
check(input) {
|
|
203
|
+
return this.client.post("/discounts/check", input, { access: "public" });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/cart.ts
|
|
208
|
+
const CART_VERSION = 1;
|
|
209
|
+
const MAX_QUANTITY = 999999;
|
|
210
|
+
function cartItemId(item) {
|
|
211
|
+
return item.productVariantId ? `${item.productId}:${item.productVariantId}` : item.productId;
|
|
212
|
+
}
|
|
213
|
+
function quantity(value, allowZero = false) {
|
|
214
|
+
const normalized = value ?? 1;
|
|
215
|
+
const minimum = allowZero ? 0 : 1;
|
|
216
|
+
if (!Number.isInteger(normalized) || normalized < minimum || normalized > MAX_QUANTITY) throw new Error(`Cart quantity must be an integer between ${minimum} and ${MAX_QUANTITY}`);
|
|
217
|
+
return normalized;
|
|
218
|
+
}
|
|
219
|
+
function cloneSnapshot(state) {
|
|
220
|
+
return {
|
|
221
|
+
items: state.items.map((item) => ({ ...item })),
|
|
222
|
+
discount: state.discount ? { ...state.discount } : null
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function isCartItem(value) {
|
|
226
|
+
if (!value || typeof value !== "object") return false;
|
|
227
|
+
const item = value;
|
|
228
|
+
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;
|
|
229
|
+
}
|
|
230
|
+
function isCartDiscount(value) {
|
|
231
|
+
if (!value || typeof value !== "object") return false;
|
|
232
|
+
const discount = value;
|
|
233
|
+
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";
|
|
234
|
+
}
|
|
235
|
+
var CartApi = class {
|
|
236
|
+
client;
|
|
237
|
+
memory = {
|
|
238
|
+
version: CART_VERSION,
|
|
239
|
+
items: [],
|
|
240
|
+
discount: null
|
|
241
|
+
};
|
|
242
|
+
constructor(client) {
|
|
243
|
+
this.client = client;
|
|
244
|
+
}
|
|
245
|
+
storageKey() {
|
|
246
|
+
const storeId = this.client.storeContextId();
|
|
247
|
+
return storeId ? `caldik:cart:${storeId}` : null;
|
|
248
|
+
}
|
|
249
|
+
read() {
|
|
250
|
+
const key = this.storageKey();
|
|
251
|
+
if (key && typeof localStorage !== "undefined") try {
|
|
252
|
+
const value = localStorage.getItem(key);
|
|
253
|
+
if (value) {
|
|
254
|
+
const parsed = JSON.parse(value);
|
|
255
|
+
if (parsed.version === CART_VERSION && Array.isArray(parsed.items) && parsed.items.every(isCartItem)) this.memory = {
|
|
256
|
+
version: CART_VERSION,
|
|
257
|
+
items: parsed.items,
|
|
258
|
+
discount: isCartDiscount(parsed.discount) ? parsed.discount : null
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
} catch {}
|
|
262
|
+
return this.memory;
|
|
263
|
+
}
|
|
264
|
+
write(state) {
|
|
265
|
+
this.memory = {
|
|
266
|
+
version: CART_VERSION,
|
|
267
|
+
...cloneSnapshot(state)
|
|
268
|
+
};
|
|
269
|
+
const key = this.storageKey();
|
|
270
|
+
if (key && typeof localStorage !== "undefined") try {
|
|
271
|
+
localStorage.setItem(key, JSON.stringify(this.memory));
|
|
272
|
+
} catch {}
|
|
273
|
+
return this.get();
|
|
274
|
+
}
|
|
275
|
+
get() {
|
|
276
|
+
return cloneSnapshot(this.read());
|
|
277
|
+
}
|
|
278
|
+
add(item) {
|
|
279
|
+
const productId = item.productId.trim();
|
|
280
|
+
const productVariantId = item.productVariantId?.trim() || "";
|
|
281
|
+
if (!productId) throw new Error("Cart productId is required");
|
|
282
|
+
const state = this.get();
|
|
283
|
+
const id = cartItemId({
|
|
284
|
+
productId,
|
|
285
|
+
productVariantId
|
|
286
|
+
});
|
|
287
|
+
const existing = state.items.find((entry) => entry.id === id);
|
|
288
|
+
const addedQuantity = quantity(item.quantity);
|
|
289
|
+
if (existing) existing.quantity = quantity(existing.quantity + addedQuantity);
|
|
290
|
+
else state.items.push({
|
|
291
|
+
id,
|
|
292
|
+
productId,
|
|
293
|
+
...productVariantId ? { productVariantId } : {},
|
|
294
|
+
quantity: addedQuantity
|
|
295
|
+
});
|
|
296
|
+
state.discount = null;
|
|
297
|
+
return this.write(state);
|
|
298
|
+
}
|
|
299
|
+
updateQuantity(itemId, nextQuantity) {
|
|
300
|
+
const state = this.get();
|
|
301
|
+
const normalized = quantity(nextQuantity, true);
|
|
302
|
+
const index = state.items.findIndex((item) => item.id === itemId);
|
|
303
|
+
if (index === -1) throw new Error("Cart item not found");
|
|
304
|
+
if (normalized === 0) state.items.splice(index, 1);
|
|
305
|
+
else state.items[index].quantity = normalized;
|
|
306
|
+
state.discount = null;
|
|
307
|
+
return this.write(state);
|
|
308
|
+
}
|
|
309
|
+
remove(itemId) {
|
|
310
|
+
const state = this.get();
|
|
311
|
+
const items = state.items.filter((item) => item.id !== itemId);
|
|
312
|
+
if (items.length === state.items.length) throw new Error("Cart item not found");
|
|
313
|
+
return this.write({
|
|
314
|
+
items,
|
|
315
|
+
discount: null
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
clear() {
|
|
319
|
+
return this.write({
|
|
320
|
+
items: [],
|
|
321
|
+
discount: null
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
commerceItems() {
|
|
325
|
+
return this.get().items.map(({ productId, productVariantId, quantity }) => ({
|
|
326
|
+
productId,
|
|
327
|
+
...productVariantId ? { productVariantId } : {},
|
|
328
|
+
quantity
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
async checkDiscount(code) {
|
|
332
|
+
const items = this.commerceItems();
|
|
333
|
+
if (items.length === 0) throw new Error("Cannot check a discount on an empty cart");
|
|
334
|
+
return this.client.post("/discounts/check", {
|
|
335
|
+
code,
|
|
336
|
+
items
|
|
337
|
+
}, { access: "public" });
|
|
338
|
+
}
|
|
339
|
+
async applyDiscount(code) {
|
|
340
|
+
const quote = await this.checkDiscount(code);
|
|
341
|
+
const state = this.get();
|
|
342
|
+
state.discount = {
|
|
343
|
+
...quote.discount,
|
|
344
|
+
subtotal: quote.subtotal,
|
|
345
|
+
discountAmount: quote.discountAmount,
|
|
346
|
+
total: quote.total,
|
|
347
|
+
currency: quote.currency
|
|
348
|
+
};
|
|
349
|
+
return this.write(state);
|
|
350
|
+
}
|
|
351
|
+
removeDiscount() {
|
|
352
|
+
const state = this.get();
|
|
353
|
+
state.discount = null;
|
|
354
|
+
return this.write(state);
|
|
355
|
+
}
|
|
356
|
+
async checkout(input) {
|
|
357
|
+
const state = this.get();
|
|
358
|
+
if (state.items.length === 0) throw new Error("Cannot checkout an empty cart");
|
|
359
|
+
const response = await this.client.post("/checkouts", {
|
|
360
|
+
...input,
|
|
361
|
+
items: this.commerceItems(),
|
|
362
|
+
...state.discount ? { discountCode: state.discount.code } : {}
|
|
363
|
+
}, { access: "public" });
|
|
364
|
+
this.clear();
|
|
365
|
+
return response;
|
|
203
366
|
}
|
|
204
367
|
};
|
|
205
368
|
//#endregion
|
|
@@ -254,7 +417,8 @@ var CaldikClient = class {
|
|
|
254
417
|
checkout;
|
|
255
418
|
customer;
|
|
256
419
|
subscriptions;
|
|
257
|
-
|
|
420
|
+
discounts;
|
|
421
|
+
cart;
|
|
258
422
|
constructor(options = {}) {
|
|
259
423
|
const client = new CaldikHttpClient({
|
|
260
424
|
apiKey: options.apiKey,
|
|
@@ -268,8 +432,9 @@ var CaldikClient = class {
|
|
|
268
432
|
this.checkout = new CheckoutApi(client);
|
|
269
433
|
this.customer = new CustomerApi(client);
|
|
270
434
|
this.subscriptions = new SubscriptionsApi(client);
|
|
271
|
-
this.
|
|
435
|
+
this.discounts = new DiscountsApi(client);
|
|
436
|
+
this.cart = new CartApi(client);
|
|
272
437
|
}
|
|
273
438
|
};
|
|
274
439
|
//#endregion
|
|
275
|
-
export { CaldikClient, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|
|
440
|
+
export { CaldikClient, CartApi, DiscountsApi, checkoutPaymentProviderIds, paymentProviderIds, storeWebhookEventNames, subscriptionPaymentProviderIds };
|