@putiikkipalvelu/storefront-sdk 0.1.1 → 0.2.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/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/errors.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/utils/errors.ts
2
2
  var StorefrontError = class _StorefrontError extends Error {
3
3
  constructor(message, status, code) {
4
4
  super(message);
@@ -165,6 +165,1135 @@ function createStoreResource(fetcher) {
165
165
  };
166
166
  }
167
167
 
168
+ // src/resources/products.ts
169
+ function createProductsResource(fetcher) {
170
+ return {
171
+ /**
172
+ * Get latest products ordered by creation date (newest first).
173
+ *
174
+ * @param take - Number of products to return (required, must be >= 1)
175
+ * @param options - Fetch options (caching, headers, etc.)
176
+ * @returns Array of products
177
+ *
178
+ * @example Basic usage
179
+ * ```typescript
180
+ * const products = await client.products.latest(6);
181
+ * ```
182
+ *
183
+ * @example Next.js - with caching
184
+ * ```typescript
185
+ * const products = await client.products.latest(6, {
186
+ * next: { revalidate: 3600, tags: ['products'] }
187
+ * });
188
+ * ```
189
+ */
190
+ async latest(take, options) {
191
+ return fetcher.request("/api/storefront/v1/latest-products", {
192
+ params: { take },
193
+ ...options
194
+ });
195
+ },
196
+ /**
197
+ * Get a single product by its URL slug.
198
+ *
199
+ * @param slug - Product URL slug
200
+ * @param options - Fetch options (caching, headers, etc.)
201
+ * @returns Full product details including categories and variations
202
+ * @throws NotFoundError if product doesn't exist or is not visible
203
+ *
204
+ * @example Basic usage
205
+ * ```typescript
206
+ * const product = await client.products.getBySlug('my-product');
207
+ * console.log(product.name, product.categories);
208
+ * ```
209
+ *
210
+ * @example Next.js - with caching
211
+ * ```typescript
212
+ * const product = await client.products.getBySlug('my-product', {
213
+ * next: { revalidate: 3600, tags: ['product', 'my-product'] }
214
+ * });
215
+ * ```
216
+ */
217
+ async getBySlug(slug, options) {
218
+ return fetcher.request(
219
+ `/api/storefront/v1/product/${encodeURIComponent(slug)}`,
220
+ {
221
+ ...options
222
+ }
223
+ );
224
+ },
225
+ /**
226
+ * Get total product count, optionally filtered by category.
227
+ *
228
+ * @param slugs - Optional category slugs to filter by
229
+ * @param options - Fetch options (caching, headers, etc.)
230
+ * @returns Object with count property
231
+ *
232
+ * @example Get total count
233
+ * ```typescript
234
+ * const { count } = await client.products.count();
235
+ * console.log(`Total products: ${count}`);
236
+ * ```
237
+ *
238
+ * @example Get count for specific category
239
+ * ```typescript
240
+ * const { count } = await client.products.count(['shoes']);
241
+ * console.log(`Products in shoes: ${count}`);
242
+ * ```
243
+ */
244
+ async count(slugs, options) {
245
+ const searchParams = new URLSearchParams();
246
+ if (_optionalChain([slugs, 'optionalAccess', _ => _.length])) {
247
+ slugs.forEach((s) => searchParams.append("slugs", s));
248
+ }
249
+ const query = searchParams.toString();
250
+ const endpoint = `/api/storefront/v1/products-count${query ? `?${query}` : ""}`;
251
+ return fetcher.request(endpoint, {
252
+ ...options
253
+ });
254
+ },
255
+ /**
256
+ * Get sorted products with pagination.
257
+ * Uses optimized sorting with pre-computed effective prices.
258
+ *
259
+ * @param params - Query parameters (slugs, page, pageSize, sort)
260
+ * @param options - Fetch options (caching, headers, etc.)
261
+ * @returns Products list with totalCount for pagination
262
+ *
263
+ * @example Basic usage
264
+ * ```typescript
265
+ * const { products, totalCount } = await client.products.sorted({
266
+ * page: 1,
267
+ * pageSize: 12,
268
+ * sort: 'newest'
269
+ * });
270
+ * ```
271
+ *
272
+ * @example Filter by category
273
+ * ```typescript
274
+ * const { products, totalCount } = await client.products.sorted({
275
+ * slugs: ['shoes', 'clothing'],
276
+ * page: 1,
277
+ * pageSize: 24,
278
+ * sort: 'price_asc'
279
+ * });
280
+ * ```
281
+ *
282
+ * @example Real-time data (no cache)
283
+ * ```typescript
284
+ * const data = await client.products.sorted(
285
+ * { page: 1, pageSize: 12 },
286
+ * { cache: 'no-store' }
287
+ * );
288
+ * ```
289
+ */
290
+ async sorted(params = {}, options) {
291
+ const searchParams = new URLSearchParams();
292
+ if (params.page) searchParams.set("page", params.page.toString());
293
+ if (params.pageSize)
294
+ searchParams.set("pageSize", params.pageSize.toString());
295
+ if (params.sort) searchParams.set("sort", params.sort);
296
+ if (_optionalChain([params, 'access', _2 => _2.slugs, 'optionalAccess', _3 => _3.length])) {
297
+ params.slugs.forEach((s) => searchParams.append("slugs", s));
298
+ }
299
+ const query = searchParams.toString();
300
+ const endpoint = `/api/storefront/v1/sorted-products${query ? `?${query}` : ""}`;
301
+ return fetcher.request(endpoint, {
302
+ ...options
303
+ });
304
+ },
305
+ /**
306
+ * Get filtered products with pagination.
307
+ * Similar to sorted() but without totalCount in response.
308
+ * Useful for sitemaps and bulk fetches.
309
+ *
310
+ * @param params - Query parameters (slugs, page, pageSize, sort)
311
+ * @param options - Fetch options (caching, headers, etc.)
312
+ * @returns Products list with category name
313
+ *
314
+ * @example Fetch all products for sitemap
315
+ * ```typescript
316
+ * const { products } = await client.products.filtered({
317
+ * slugs: ['all-products'],
318
+ * page: 1,
319
+ * pageSize: 1000
320
+ * });
321
+ * ```
322
+ */
323
+ async filtered(params = {}, options) {
324
+ const searchParams = new URLSearchParams();
325
+ if (params.page) searchParams.set("page", params.page.toString());
326
+ if (params.pageSize)
327
+ searchParams.set("pageSize", params.pageSize.toString());
328
+ if (params.sort) searchParams.set("sort", params.sort);
329
+ if (_optionalChain([params, 'access', _4 => _4.slugs, 'optionalAccess', _5 => _5.length])) {
330
+ params.slugs.forEach((s) => searchParams.append("slugs", s));
331
+ }
332
+ const query = searchParams.toString();
333
+ const endpoint = `/api/storefront/v1/filtered-products${query ? `?${query}` : ""}`;
334
+ return fetcher.request(
335
+ endpoint,
336
+ {
337
+ ...options
338
+ }
339
+ );
340
+ }
341
+ };
342
+ }
343
+
344
+ // src/resources/categories.ts
345
+ function createCategoriesResource(fetcher) {
346
+ return {
347
+ /**
348
+ * Get all top-level categories with nested children.
349
+ * Returns a hierarchical tree of categories (up to 5 levels deep).
350
+ *
351
+ * @param options - Fetch options (caching, headers, etc.)
352
+ * @returns Array of top-level categories with nested children
353
+ *
354
+ * @example Basic usage
355
+ * ```typescript
356
+ * const categories = await client.categories.list();
357
+ * categories.forEach(cat => {
358
+ * console.log(cat.name, cat.children.length);
359
+ * });
360
+ * ```
361
+ *
362
+ * @example Next.js - with caching
363
+ * ```typescript
364
+ * const categories = await client.categories.list({
365
+ * next: { revalidate: 3600, tags: ['categories'] }
366
+ * });
367
+ * ```
368
+ */
369
+ async list(options) {
370
+ return fetcher.request("/api/storefront/v1/categories", {
371
+ ...options
372
+ });
373
+ },
374
+ /**
375
+ * Get a single category by its URL slug.
376
+ *
377
+ * @param slug - Category URL slug
378
+ * @param options - Fetch options (caching, headers, etc.)
379
+ * @returns Category data
380
+ * @throws NotFoundError if category doesn't exist
381
+ *
382
+ * @example Basic usage
383
+ * ```typescript
384
+ * const { category } = await client.categories.getBySlug('shoes');
385
+ * console.log(category.name);
386
+ * ```
387
+ *
388
+ * @example Next.js - with caching
389
+ * ```typescript
390
+ * const { category } = await client.categories.getBySlug('shoes', {
391
+ * next: { revalidate: 86400, tags: ['category', 'shoes'] }
392
+ * });
393
+ * ```
394
+ */
395
+ async getBySlug(slug, options) {
396
+ return fetcher.request(
397
+ `/api/storefront/v1/categories/${encodeURIComponent(slug)}`,
398
+ {
399
+ ...options
400
+ }
401
+ );
402
+ }
403
+ };
404
+ }
405
+
406
+ // src/resources/cart.ts
407
+ function buildCartHeaders(options) {
408
+ const headers = {};
409
+ if (_optionalChain([options, 'optionalAccess', _6 => _6.cartId])) {
410
+ headers["x-cart-id"] = options.cartId;
411
+ }
412
+ if (_optionalChain([options, 'optionalAccess', _7 => _7.sessionId])) {
413
+ headers["x-session-id"] = options.sessionId;
414
+ }
415
+ return headers;
416
+ }
417
+ function createCartResource(fetcher) {
418
+ return {
419
+ /**
420
+ * Fetch the current cart contents.
421
+ *
422
+ * @param options - Cart session options (cartId for guests, sessionId for logged-in users)
423
+ * @param fetchOptions - Fetch options (caching, headers, etc.)
424
+ * @returns Cart items and cartId (for guests)
425
+ *
426
+ * @example Guest user
427
+ * ```typescript
428
+ * const cartId = localStorage.getItem('cart-id');
429
+ * const { items, cartId: newCartId } = await client.cart.get({ cartId });
430
+ * ```
431
+ *
432
+ * @example Logged-in user
433
+ * ```typescript
434
+ * const { items } = await client.cart.get({ sessionId });
435
+ * ```
436
+ */
437
+ async get(options, fetchOptions) {
438
+ return fetcher.request("/api/storefront/v1/cart", {
439
+ method: "GET",
440
+ headers: buildCartHeaders(options),
441
+ ...fetchOptions
442
+ });
443
+ },
444
+ /**
445
+ * Add an item to the cart.
446
+ * If the item already exists, quantity is incremented.
447
+ *
448
+ * @param params - Add to cart parameters
449
+ * @param fetchOptions - Fetch options
450
+ * @returns Updated cart with new cartId for guests
451
+ * @throws ValidationError if quantity exceeds available stock
452
+ *
453
+ * @example Add product
454
+ * ```typescript
455
+ * const { items, cartId } = await client.cart.addItem({
456
+ * cartId: existingCartId,
457
+ * productId: 'prod_123',
458
+ * quantity: 2
459
+ * });
460
+ * // Save cartId for future requests
461
+ * localStorage.setItem('cart-id', cartId);
462
+ * ```
463
+ *
464
+ * @example Add product with variation
465
+ * ```typescript
466
+ * const { items, cartId } = await client.cart.addItem({
467
+ * cartId,
468
+ * productId: 'prod_123',
469
+ * variationId: 'var_456',
470
+ * quantity: 1
471
+ * });
472
+ * ```
473
+ */
474
+ async addItem(params, fetchOptions) {
475
+ const { cartId, sessionId, ...body } = params;
476
+ return fetcher.request("/api/storefront/v1/cart", {
477
+ method: "POST",
478
+ headers: buildCartHeaders({ sessionId }),
479
+ body: {
480
+ cartId,
481
+ ...body
482
+ },
483
+ ...fetchOptions
484
+ });
485
+ },
486
+ /**
487
+ * Update item quantity by delta (atomic operation).
488
+ * Use positive delta to increase, negative to decrease.
489
+ * Minimum quantity is 1 (use removeItem to delete).
490
+ *
491
+ * @param params - Update quantity parameters
492
+ * @param fetchOptions - Fetch options
493
+ * @returns Updated cart
494
+ * @throws NotFoundError if item not in cart or quantity would go below 1
495
+ *
496
+ * @example Increment quantity
497
+ * ```typescript
498
+ * const { items } = await client.cart.updateQuantity({
499
+ * cartId,
500
+ * productId: 'prod_123',
501
+ * delta: 1
502
+ * });
503
+ * ```
504
+ *
505
+ * @example Decrement quantity
506
+ * ```typescript
507
+ * const { items } = await client.cart.updateQuantity({
508
+ * cartId,
509
+ * productId: 'prod_123',
510
+ * variationId: 'var_456',
511
+ * delta: -1
512
+ * });
513
+ * ```
514
+ */
515
+ async updateQuantity(params, fetchOptions) {
516
+ const { cartId, sessionId, ...body } = params;
517
+ return fetcher.request("/api/storefront/v1/cart", {
518
+ method: "PATCH",
519
+ headers: buildCartHeaders({ sessionId }),
520
+ body: {
521
+ cartId,
522
+ ...body
523
+ },
524
+ ...fetchOptions
525
+ });
526
+ },
527
+ /**
528
+ * Remove an item from the cart.
529
+ *
530
+ * @param params - Remove from cart parameters
531
+ * @param fetchOptions - Fetch options
532
+ * @returns Updated cart
533
+ *
534
+ * @example Remove product
535
+ * ```typescript
536
+ * const { items } = await client.cart.removeItem({
537
+ * cartId,
538
+ * productId: 'prod_123'
539
+ * });
540
+ * ```
541
+ *
542
+ * @example Remove variation
543
+ * ```typescript
544
+ * const { items } = await client.cart.removeItem({
545
+ * cartId,
546
+ * productId: 'prod_123',
547
+ * variationId: 'var_456'
548
+ * });
549
+ * ```
550
+ */
551
+ async removeItem(params, fetchOptions) {
552
+ const { cartId, sessionId, ...body } = params;
553
+ return fetcher.request("/api/storefront/v1/cart", {
554
+ method: "DELETE",
555
+ headers: buildCartHeaders({ sessionId }),
556
+ body: {
557
+ cartId,
558
+ ...body
559
+ },
560
+ ...fetchOptions
561
+ });
562
+ },
563
+ /**
564
+ * Validate cart before checkout.
565
+ * Checks product availability, stock levels, and prices.
566
+ * Auto-fixes issues (removes unavailable items, adjusts quantities).
567
+ *
568
+ * @param options - Cart session options
569
+ * @param fetchOptions - Fetch options
570
+ * @returns Validated cart with change metadata
571
+ *
572
+ * @example Validate before checkout
573
+ * ```typescript
574
+ * const { items, hasChanges, changes } = await client.cart.validate({ cartId });
575
+ *
576
+ * if (hasChanges) {
577
+ * if (changes.removedItems > 0) {
578
+ * notify('Some items were removed (out of stock)');
579
+ * }
580
+ * if (changes.quantityAdjusted > 0) {
581
+ * notify('Some quantities were adjusted');
582
+ * }
583
+ * if (changes.priceChanged > 0) {
584
+ * notify('Some prices have changed');
585
+ * }
586
+ * }
587
+ * ```
588
+ */
589
+ async validate(options, fetchOptions) {
590
+ return fetcher.request(
591
+ "/api/storefront/v1/cart/validate",
592
+ {
593
+ method: "GET",
594
+ headers: buildCartHeaders(options),
595
+ ...fetchOptions
596
+ }
597
+ );
598
+ }
599
+ };
600
+ }
601
+
602
+ // src/resources/shipping.ts
603
+ function createShippingResource(fetcher) {
604
+ return {
605
+ /**
606
+ * Get all available shipment methods for the store.
607
+ * Returns methods without pickup locations - use `getWithLocations` for postal code specific data.
608
+ *
609
+ * @param options - Fetch options (caching, headers, etc.)
610
+ * @returns Available shipment methods
611
+ *
612
+ * @example
613
+ * ```typescript
614
+ * const { shipmentMethods } = await client.shipping.getMethods();
615
+ *
616
+ * shipmentMethods.forEach(method => {
617
+ * console.log(`${method.name}: ${method.price / 100}€`);
618
+ * });
619
+ * ```
620
+ */
621
+ async getMethods(options) {
622
+ return fetcher.request(
623
+ "/api/storefront/v1/shipment-methods",
624
+ {
625
+ method: "GET",
626
+ ...options
627
+ }
628
+ );
629
+ },
630
+ /**
631
+ * Get shipment methods with pickup locations for a specific postal code.
632
+ * Calls the Shipit API to fetch nearby pickup points (parcel lockers, etc.)
633
+ *
634
+ * @param postalCode - Customer's postal code (e.g., "00100")
635
+ * @param options - Fetch options (caching, headers, etc.)
636
+ * @returns Shipment methods and nearby pickup locations with pricing
637
+ *
638
+ * @example
639
+ * ```typescript
640
+ * const { shipmentMethods, pricedLocations } = await client.shipping.getWithLocations("00100");
641
+ *
642
+ * // Show pickup locations
643
+ * pricedLocations.forEach(location => {
644
+ * console.log(`${location.name} - ${location.carrier}`);
645
+ * console.log(` ${location.address1}, ${location.city}`);
646
+ * console.log(` ${location.distanceInKilometers.toFixed(1)} km away`);
647
+ * console.log(` Price: ${(location.merchantPrice ?? 0) / 100}€`);
648
+ * });
649
+ * ```
650
+ *
651
+ * @example Filter by carrier
652
+ * ```typescript
653
+ * const { pricedLocations } = await client.shipping.getWithLocations("00100");
654
+ *
655
+ * const postiLocations = pricedLocations.filter(
656
+ * loc => loc.carrier === "Posti"
657
+ * );
658
+ * ```
659
+ */
660
+ async getWithLocations(postalCode, options) {
661
+ return fetcher.request(
662
+ `/api/storefront/v1/shipment-methods/${encodeURIComponent(postalCode)}`,
663
+ {
664
+ method: "GET",
665
+ ...options
666
+ }
667
+ );
668
+ }
669
+ };
670
+ }
671
+
672
+ // src/resources/customer.ts
673
+ function buildSessionHeaders(sessionId) {
674
+ return { "x-session-id": sessionId };
675
+ }
676
+ function createCustomerResource(fetcher) {
677
+ return {
678
+ /**
679
+ * Register a new customer account.
680
+ * After registration, the customer must verify their email before logging in.
681
+ *
682
+ * @param data - Registration data (firstName, lastName, email, password)
683
+ * @param fetchOptions - Fetch options
684
+ * @returns Created customer with verification token
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * const { customer, message } = await client.customer.register({
689
+ * firstName: 'John',
690
+ * lastName: 'Doe',
691
+ * email: 'john@example.com',
692
+ * password: 'securePassword123'
693
+ * });
694
+ *
695
+ * // Send verification email using customer.emailVerificationToken
696
+ * console.log('Account created:', message);
697
+ * ```
698
+ */
699
+ async register(data, fetchOptions) {
700
+ return fetcher.request(
701
+ "/api/storefront/v1/customer/(auth)/register",
702
+ {
703
+ method: "POST",
704
+ body: data,
705
+ ...fetchOptions
706
+ }
707
+ );
708
+ },
709
+ /**
710
+ * Log in an existing customer.
711
+ * Returns a session ID that must be stored and passed to authenticated endpoints.
712
+ *
713
+ * @param email - Customer's email address
714
+ * @param password - Customer's password
715
+ * @param options - Login options (optional cartId for cart merging)
716
+ * @param fetchOptions - Fetch options
717
+ * @returns Session ID and customer data
718
+ * @throws ValidationError if email is not verified (check error for requiresVerification)
719
+ *
720
+ * @example
721
+ * ```typescript
722
+ * try {
723
+ * const { sessionId, customer, expiresAt } = await client.customer.login(
724
+ * 'john@example.com',
725
+ * 'securePassword123',
726
+ * { cartId: guestCartId } // Optional: merge guest cart
727
+ * );
728
+ *
729
+ * // Store sessionId in a cookie
730
+ * cookies().set('session-id', sessionId, {
731
+ * httpOnly: true,
732
+ * expires: new Date(expiresAt)
733
+ * });
734
+ * } catch (error) {
735
+ * if (error.requiresVerification) {
736
+ * // Prompt user to verify email
737
+ * await client.customer.resendVerification(error.customerId);
738
+ * }
739
+ * }
740
+ * ```
741
+ */
742
+ async login(email, password, options, fetchOptions) {
743
+ const headers = {};
744
+ if (_optionalChain([options, 'optionalAccess', _8 => _8.cartId])) {
745
+ headers["x-cart-id"] = options.cartId;
746
+ }
747
+ return fetcher.request(
748
+ "/api/storefront/v1/customer/(auth)/login",
749
+ {
750
+ method: "POST",
751
+ body: { email, password },
752
+ headers,
753
+ ...fetchOptions
754
+ }
755
+ );
756
+ },
757
+ /**
758
+ * Log out the current customer and invalidate their session.
759
+ * If the customer had items in their cart, they are migrated to a new guest cart.
760
+ *
761
+ * @param sessionId - The customer's session ID
762
+ * @param fetchOptions - Fetch options
763
+ * @returns Logout confirmation with optional new guest cart ID
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * const { cartId } = await client.customer.logout(sessionId);
768
+ *
769
+ * // Clear session cookie
770
+ * cookies().delete('session-id');
771
+ *
772
+ * // If cart was migrated, store the new guest cart ID
773
+ * if (cartId) {
774
+ * cookies().set('cart-id', cartId);
775
+ * }
776
+ * ```
777
+ */
778
+ async logout(sessionId, fetchOptions) {
779
+ return fetcher.request(
780
+ "/api/storefront/v1/customer/(auth)/logout",
781
+ {
782
+ method: "POST",
783
+ headers: buildSessionHeaders(sessionId),
784
+ ...fetchOptions
785
+ }
786
+ );
787
+ },
788
+ /**
789
+ * Get the currently authenticated customer's profile.
790
+ *
791
+ * @param sessionId - The customer's session ID
792
+ * @param fetchOptions - Fetch options
793
+ * @returns Current customer data
794
+ * @throws AuthError if session is invalid or expired
795
+ *
796
+ * @example
797
+ * ```typescript
798
+ * const sessionId = cookies().get('session-id')?.value;
799
+ * if (sessionId) {
800
+ * const { customer } = await client.customer.getUser(sessionId);
801
+ * console.log(`Welcome back, ${customer.firstName}!`);
802
+ * }
803
+ * ```
804
+ */
805
+ async getUser(sessionId, fetchOptions) {
806
+ return fetcher.request(
807
+ "/api/storefront/v1/customer/(auth)/get-user",
808
+ {
809
+ method: "GET",
810
+ headers: buildSessionHeaders(sessionId),
811
+ ...fetchOptions
812
+ }
813
+ );
814
+ },
815
+ /**
816
+ * Verify a customer's email address using the token sent during registration.
817
+ *
818
+ * @param token - Email verification token
819
+ * @param fetchOptions - Fetch options
820
+ * @returns Verification confirmation
821
+ * @throws ValidationError if token is invalid or expired
822
+ *
823
+ * @example
824
+ * ```typescript
825
+ * // Token comes from the verification email link
826
+ * const token = searchParams.get('token');
827
+ *
828
+ * const { message } = await client.customer.verifyEmail(token);
829
+ * console.log(message); // "Email verified successfully. You can now log in."
830
+ * ```
831
+ */
832
+ async verifyEmail(token, fetchOptions) {
833
+ return fetcher.request(
834
+ "/api/storefront/v1/customer/(auth)/verify-email",
835
+ {
836
+ method: "GET",
837
+ params: { token },
838
+ ...fetchOptions
839
+ }
840
+ );
841
+ },
842
+ /**
843
+ * Resend the email verification token for an unverified customer.
844
+ * Generates a new token valid for 24 hours.
845
+ *
846
+ * @param customerId - The customer's ID (from failed login response)
847
+ * @param fetchOptions - Fetch options
848
+ * @returns Updated customer with new verification token
849
+ * @throws ValidationError if customer is already verified or not found
850
+ *
851
+ * @example
852
+ * ```typescript
853
+ * // After login fails with requiresVerification
854
+ * const { customer } = await client.customer.resendVerification(customerId);
855
+ *
856
+ * // Send new verification email using customer.emailVerificationToken
857
+ * await sendVerificationEmail(customer.email, customer.emailVerificationToken);
858
+ * ```
859
+ */
860
+ async resendVerification(customerId, fetchOptions) {
861
+ return fetcher.request(
862
+ "/api/storefront/v1/customer/(auth)/resend-verification",
863
+ {
864
+ method: "POST",
865
+ body: { customerId },
866
+ ...fetchOptions
867
+ }
868
+ );
869
+ },
870
+ // =========================================================================
871
+ // Profile Management Methods
872
+ // =========================================================================
873
+ /**
874
+ * Update the authenticated customer's profile.
875
+ *
876
+ * @param sessionId - The customer's session ID
877
+ * @param data - Profile data to update (firstName, lastName, email)
878
+ * @param fetchOptions - Fetch options
879
+ * @returns Updated customer data
880
+ * @throws AuthError if session is invalid
881
+ * @throws ValidationError if email is already taken by another customer
882
+ *
883
+ * @example
884
+ * ```typescript
885
+ * const { customer } = await client.customer.updateProfile(sessionId, {
886
+ * firstName: 'Jane',
887
+ * lastName: 'Smith',
888
+ * email: 'jane.smith@example.com'
889
+ * });
890
+ *
891
+ * console.log('Profile updated:', customer.email);
892
+ * ```
893
+ */
894
+ async updateProfile(sessionId, data, fetchOptions) {
895
+ return fetcher.request(
896
+ "/api/storefront/v1/customer/edit-user",
897
+ {
898
+ method: "PATCH",
899
+ headers: buildSessionHeaders(sessionId),
900
+ body: data,
901
+ ...fetchOptions
902
+ }
903
+ );
904
+ },
905
+ /**
906
+ * Delete the authenticated customer's account.
907
+ * This action is permanent and cannot be undone.
908
+ * All associated data (sessions, wishlist, etc.) will be deleted.
909
+ *
910
+ * @param sessionId - The customer's session ID
911
+ * @param fetchOptions - Fetch options
912
+ * @returns Deletion confirmation
913
+ * @throws AuthError if session is invalid
914
+ *
915
+ * @example
916
+ * ```typescript
917
+ * // Confirm with user before calling
918
+ * if (confirm('Are you sure you want to delete your account?')) {
919
+ * await client.customer.deleteAccount(sessionId);
920
+ *
921
+ * // Clear session cookie
922
+ * cookies().delete('session-id');
923
+ *
924
+ * // Redirect to home page
925
+ * redirect('/');
926
+ * }
927
+ * ```
928
+ */
929
+ async deleteAccount(sessionId, fetchOptions) {
930
+ return fetcher.request(
931
+ "/api/storefront/v1/customer/delete-user",
932
+ {
933
+ method: "DELETE",
934
+ headers: buildSessionHeaders(sessionId),
935
+ ...fetchOptions
936
+ }
937
+ );
938
+ },
939
+ /**
940
+ * Get the customer's order history.
941
+ * Returns all orders with line items and product details.
942
+ *
943
+ * @param sessionId - The customer's session ID
944
+ * @param customerId - The customer's ID
945
+ * @param fetchOptions - Fetch options
946
+ * @returns List of customer orders
947
+ *
948
+ * @example
949
+ * ```typescript
950
+ * const { orders } = await client.customer.getOrders(sessionId, customerId);
951
+ *
952
+ * orders.forEach(order => {
953
+ * console.log(`Order #${order.orderNumber}: ${order.status}`);
954
+ * order.OrderLineItems.forEach(item => {
955
+ * console.log(` - ${item.name} x${item.quantity}`);
956
+ * });
957
+ * });
958
+ * ```
959
+ */
960
+ async getOrders(sessionId, customerId, fetchOptions) {
961
+ return fetcher.request(
962
+ `/api/storefront/v1/customer/get-orders/${customerId}`,
963
+ {
964
+ method: "GET",
965
+ headers: buildSessionHeaders(sessionId),
966
+ ...fetchOptions
967
+ }
968
+ );
969
+ },
970
+ // =========================================================================
971
+ // Wishlist (Nested Resource)
972
+ // =========================================================================
973
+ /**
974
+ * Wishlist management methods.
975
+ * Access via `client.customer.wishlist.get()`, `.add()`, `.remove()`.
976
+ */
977
+ wishlist: {
978
+ /**
979
+ * Get the customer's wishlist.
980
+ * Returns all wishlist items with product and variation details.
981
+ *
982
+ * @param sessionId - The customer's session ID
983
+ * @param fetchOptions - Fetch options
984
+ * @returns Wishlist items with product details
985
+ * @throws AuthError if session is invalid
986
+ *
987
+ * @example
988
+ * ```typescript
989
+ * const { items } = await client.customer.wishlist.get(sessionId);
990
+ *
991
+ * items.forEach(item => {
992
+ * console.log(`${item.product.name} - $${item.product.price / 100}`);
993
+ * if (item.variation) {
994
+ * const options = item.variation.options
995
+ * .map(o => `${o.optionType.name}: ${o.value}`)
996
+ * .join(', ');
997
+ * console.log(` Variant: ${options}`);
998
+ * }
999
+ * });
1000
+ * ```
1001
+ */
1002
+ async get(sessionId, fetchOptions) {
1003
+ return fetcher.request(
1004
+ "/api/storefront/v1/customer/wishlist",
1005
+ {
1006
+ method: "GET",
1007
+ headers: buildSessionHeaders(sessionId),
1008
+ ...fetchOptions
1009
+ }
1010
+ );
1011
+ },
1012
+ /**
1013
+ * Add a product to the customer's wishlist.
1014
+ *
1015
+ * @param sessionId - The customer's session ID
1016
+ * @param productId - The product ID to add
1017
+ * @param variationId - Optional variation ID (for products with variations)
1018
+ * @param fetchOptions - Fetch options
1019
+ * @returns Success message
1020
+ * @throws AuthError if session is invalid
1021
+ * @throws ValidationError if product already in wishlist
1022
+ *
1023
+ * @example
1024
+ * ```typescript
1025
+ * // Add a simple product
1026
+ * await client.customer.wishlist.add(sessionId, 'prod_123');
1027
+ *
1028
+ * // Add a product with a specific variation
1029
+ * await client.customer.wishlist.add(sessionId, 'prod_123', 'var_456');
1030
+ * ```
1031
+ */
1032
+ async add(sessionId, productId, variationId, fetchOptions) {
1033
+ return fetcher.request(
1034
+ "/api/storefront/v1/customer/wishlist",
1035
+ {
1036
+ method: "POST",
1037
+ headers: buildSessionHeaders(sessionId),
1038
+ body: { productId, variationId },
1039
+ ...fetchOptions
1040
+ }
1041
+ );
1042
+ },
1043
+ /**
1044
+ * Remove a product from the customer's wishlist.
1045
+ *
1046
+ * @param sessionId - The customer's session ID
1047
+ * @param productId - The product ID to remove
1048
+ * @param variationId - Optional variation ID (must match if item was added with variation)
1049
+ * @param fetchOptions - Fetch options
1050
+ * @returns Success message
1051
+ * @throws AuthError if session is invalid
1052
+ * @throws NotFoundError if item not in wishlist
1053
+ *
1054
+ * @example
1055
+ * ```typescript
1056
+ * // Remove a simple product
1057
+ * await client.customer.wishlist.remove(sessionId, 'prod_123');
1058
+ *
1059
+ * // Remove a specific variation
1060
+ * await client.customer.wishlist.remove(sessionId, 'prod_123', 'var_456');
1061
+ * ```
1062
+ */
1063
+ async remove(sessionId, productId, variationId, fetchOptions) {
1064
+ return fetcher.request(
1065
+ "/api/storefront/v1/customer/wishlist",
1066
+ {
1067
+ method: "DELETE",
1068
+ headers: buildSessionHeaders(sessionId),
1069
+ body: { productId, variationId },
1070
+ ...fetchOptions
1071
+ }
1072
+ );
1073
+ }
1074
+ }
1075
+ };
1076
+ }
1077
+
1078
+ // src/resources/order.ts
1079
+ function createOrderResource(fetcher) {
1080
+ return {
1081
+ /**
1082
+ * Get order details by ID.
1083
+ *
1084
+ * Retrieves complete order information including line items,
1085
+ * customer data, and shipment method with tracking info.
1086
+ *
1087
+ * @param orderId - The order ID to fetch
1088
+ * @param options - Fetch options (caching, headers, etc.)
1089
+ * @returns Complete order details
1090
+ * @throws NotFoundError if order doesn't exist or belongs to different store
1091
+ *
1092
+ * @example Basic usage (order confirmation page)
1093
+ * ```typescript
1094
+ * const order = await client.order.get(orderId);
1095
+ * console.log(`Order #${order.orderNumber} - ${order.status}`);
1096
+ * console.log(`Total: ${order.totalAmount / 100} EUR`);
1097
+ * ```
1098
+ *
1099
+ * @example Next.js - with caching
1100
+ * ```typescript
1101
+ * const order = await client.order.get(orderId, {
1102
+ * next: { revalidate: 60, tags: ['order', orderId] }
1103
+ * });
1104
+ * ```
1105
+ *
1106
+ * @example Display line items
1107
+ * ```typescript
1108
+ * const order = await client.order.get(orderId);
1109
+ * order.OrderLineItems.forEach(item => {
1110
+ * if (item.itemType !== 'SHIPPING') {
1111
+ * console.log(`${item.name} x${item.quantity} = ${item.totalAmount / 100} EUR`);
1112
+ * }
1113
+ * });
1114
+ * ```
1115
+ *
1116
+ * @example Show tracking info
1117
+ * ```typescript
1118
+ * const order = await client.order.get(orderId);
1119
+ * if (order.orderShipmentMethod?.trackingNumber) {
1120
+ * console.log(`Tracking: ${order.orderShipmentMethod.trackingNumber}`);
1121
+ * order.orderShipmentMethod.trackingUrls?.forEach(url => {
1122
+ * console.log(`Track at: ${url}`);
1123
+ * });
1124
+ * }
1125
+ * ```
1126
+ */
1127
+ async get(orderId, options) {
1128
+ return fetcher.request(
1129
+ `/api/storefront/v1/order/${encodeURIComponent(orderId)}`,
1130
+ {
1131
+ ...options
1132
+ }
1133
+ );
1134
+ }
1135
+ };
1136
+ }
1137
+
1138
+ // src/resources/checkout.ts
1139
+ function createCheckoutResource(fetcher) {
1140
+ function buildCheckoutHeaders(options) {
1141
+ const headers = {};
1142
+ if (_optionalChain([options, 'optionalAccess', _9 => _9.cartId])) {
1143
+ headers["x-cart-id"] = options.cartId;
1144
+ }
1145
+ if (_optionalChain([options, 'optionalAccess', _10 => _10.sessionId])) {
1146
+ headers["x-session-id"] = options.sessionId;
1147
+ }
1148
+ return headers;
1149
+ }
1150
+ function buildCheckoutBody(params) {
1151
+ return {
1152
+ orderId: params.orderId,
1153
+ chosenShipmentMethod: params.shipmentMethod,
1154
+ customerData: params.customerData,
1155
+ successUrl: params.successUrl,
1156
+ cancelUrl: params.cancelUrl
1157
+ };
1158
+ }
1159
+ return {
1160
+ /**
1161
+ * Create a Stripe checkout session.
1162
+ *
1163
+ * Redirects the user to Stripe's hosted checkout page.
1164
+ * Cart items are validated and stock is reserved on the server.
1165
+ *
1166
+ * @param params - Checkout parameters (customer data, shipping, URLs)
1167
+ * @param options - Checkout options including cart/session context
1168
+ * @returns URL to redirect user to Stripe checkout
1169
+ * @throws ValidationError for invalid data or empty cart
1170
+ * @throws StorefrontError for inventory issues
1171
+ *
1172
+ * @example Basic usage with redirect
1173
+ * ```typescript
1174
+ * const { url } = await client.checkout.stripe({
1175
+ * customerData: {
1176
+ * first_name: "John",
1177
+ * last_name: "Doe",
1178
+ * email: "john@example.com",
1179
+ * address: "123 Main St",
1180
+ * postal_code: "00100",
1181
+ * city: "Helsinki",
1182
+ * phone: "+358401234567"
1183
+ * },
1184
+ * shipmentMethod: {
1185
+ * shipmentMethodId: "ship_123",
1186
+ * pickupId: null
1187
+ * },
1188
+ * orderId: "order_abc123",
1189
+ * successUrl: "https://mystore.com/success",
1190
+ * cancelUrl: "https://mystore.com/cancel"
1191
+ * }, {
1192
+ * cartId: "cart_xyz", // For guest users
1193
+ * sessionId: "sess_123" // For logged-in users
1194
+ * });
1195
+ *
1196
+ * // Redirect to Stripe
1197
+ * window.location.href = url;
1198
+ * ```
1199
+ */
1200
+ async stripe(params, options) {
1201
+ const headers = buildCheckoutHeaders(options);
1202
+ const body = buildCheckoutBody(params);
1203
+ return fetcher.request(
1204
+ "/api/storefront/v1/payments/stripe/checkout",
1205
+ {
1206
+ method: "POST",
1207
+ body,
1208
+ headers: {
1209
+ ..._optionalChain([options, 'optionalAccess', _11 => _11.headers]),
1210
+ ...headers
1211
+ },
1212
+ ...options
1213
+ }
1214
+ );
1215
+ },
1216
+ /**
1217
+ * Create a Paytrail checkout session.
1218
+ *
1219
+ * Returns payment providers for Finnish payment methods.
1220
+ * Cart items are validated and stock is reserved on the server.
1221
+ *
1222
+ * @param params - Checkout parameters (customer data, shipping, URLs)
1223
+ * @param options - Checkout options including cart/session context
1224
+ * @returns Paytrail response with available payment providers
1225
+ * @throws ValidationError for invalid data or empty cart
1226
+ * @throws StorefrontError for inventory issues
1227
+ *
1228
+ * @example Display payment providers
1229
+ * ```typescript
1230
+ * const response = await client.checkout.paytrail({
1231
+ * customerData: {
1232
+ * first_name: "Matti",
1233
+ * last_name: "Meikäläinen",
1234
+ * email: "matti@example.fi",
1235
+ * address: "Mannerheimintie 1",
1236
+ * postal_code: "00100",
1237
+ * city: "Helsinki",
1238
+ * phone: "+358401234567"
1239
+ * },
1240
+ * shipmentMethod: {
1241
+ * shipmentMethodId: "ship_123",
1242
+ * pickupId: "pickup_456" // For pickup points
1243
+ * },
1244
+ * orderId: "order_abc123",
1245
+ * successUrl: "https://mystore.com/success",
1246
+ * cancelUrl: "https://mystore.com/cancel"
1247
+ * }, {
1248
+ * cartId: "cart_xyz"
1249
+ * });
1250
+ *
1251
+ * // Group providers by type
1252
+ * const banks = response.providers.filter(p => p.group === "bank");
1253
+ * const mobile = response.providers.filter(p => p.group === "mobile");
1254
+ * const cards = response.providers.filter(p => p.group === "creditcard");
1255
+ * ```
1256
+ *
1257
+ * @example Submit payment form
1258
+ * ```typescript
1259
+ * const provider = response.providers.find(p => p.id === "nordea");
1260
+ *
1261
+ * // Create and submit a form
1262
+ * const form = document.createElement("form");
1263
+ * form.method = "POST";
1264
+ * form.action = provider.url;
1265
+ *
1266
+ * provider.parameters.forEach(({ name, value }) => {
1267
+ * const input = document.createElement("input");
1268
+ * input.type = "hidden";
1269
+ * input.name = name;
1270
+ * input.value = value;
1271
+ * form.appendChild(input);
1272
+ * });
1273
+ *
1274
+ * document.body.appendChild(form);
1275
+ * form.submit();
1276
+ * ```
1277
+ */
1278
+ async paytrail(params, options) {
1279
+ const headers = buildCheckoutHeaders(options);
1280
+ const body = buildCheckoutBody(params);
1281
+ return fetcher.request(
1282
+ "/api/storefront/v1/payments/paytrail/checkout",
1283
+ {
1284
+ method: "POST",
1285
+ body,
1286
+ headers: {
1287
+ ..._optionalChain([options, 'optionalAccess', _12 => _12.headers]),
1288
+ ...headers
1289
+ },
1290
+ ...options
1291
+ }
1292
+ );
1293
+ }
1294
+ };
1295
+ }
1296
+
168
1297
  // src/client.ts
169
1298
  function createStorefrontClient(config) {
170
1299
  if (!config.apiKey) {
@@ -183,7 +1312,183 @@ function createStorefrontClient(config) {
183
1312
  return {
184
1313
  apiKey: maskedApiKey,
185
1314
  baseUrl,
186
- store: createStoreResource(fetcher)
1315
+ store: createStoreResource(fetcher),
1316
+ products: createProductsResource(fetcher),
1317
+ categories: createCategoriesResource(fetcher),
1318
+ cart: createCartResource(fetcher),
1319
+ shipping: createShippingResource(fetcher),
1320
+ customer: createCustomerResource(fetcher),
1321
+ order: createOrderResource(fetcher),
1322
+ checkout: createCheckoutResource(fetcher)
1323
+ };
1324
+ }
1325
+
1326
+ // src/utils/pricing.ts
1327
+ function isSaleActive(startDate, endDate) {
1328
+ if (!startDate && !endDate) {
1329
+ return true;
1330
+ }
1331
+ const now = /* @__PURE__ */ new Date();
1332
+ const start = startDate ? new Date(startDate) : null;
1333
+ const end = endDate ? new Date(endDate) : null;
1334
+ if (start && !end) {
1335
+ return now >= start;
1336
+ }
1337
+ if (!start && end) {
1338
+ return now <= end;
1339
+ }
1340
+ if (start && end) {
1341
+ return now >= start && now <= end;
1342
+ }
1343
+ return true;
1344
+ }
1345
+ function getPriceInfo(product, variation) {
1346
+ if (variation) {
1347
+ const isOnSale2 = isSaleActive(variation.saleStartDate, variation.saleEndDate) && variation.salePrice !== null;
1348
+ const originalPrice2 = _nullishCoalesce(variation.price, () => ( product.price));
1349
+ const effectivePrice2 = isOnSale2 ? _nullishCoalesce(variation.salePrice, () => ( originalPrice2)) : originalPrice2;
1350
+ return {
1351
+ effectivePrice: effectivePrice2,
1352
+ originalPrice: originalPrice2,
1353
+ isOnSale: isOnSale2,
1354
+ salePercent: isOnSale2 ? _nullishCoalesce(variation.salePercent, () => ( null)) : null
1355
+ };
1356
+ }
1357
+ const isOnSale = isSaleActive(product.saleStartDate, product.saleEndDate) && product.salePrice !== null;
1358
+ const originalPrice = product.price;
1359
+ const effectivePrice = isOnSale ? _nullishCoalesce(product.salePrice, () => ( originalPrice)) : originalPrice;
1360
+ return {
1361
+ effectivePrice,
1362
+ originalPrice,
1363
+ isOnSale,
1364
+ salePercent: isOnSale ? _nullishCoalesce(product.salePercent, () => ( null)) : null
1365
+ };
1366
+ }
1367
+
1368
+ // src/utils/cart-calculations.ts
1369
+ function calculateCartWithCampaigns(items, campaigns) {
1370
+ const freeShippingCampaign = campaigns.find(
1371
+ (c) => c.type === "FREE_SHIPPING" && c.isActive
1372
+ );
1373
+ const buyXPayYCampaign = campaigns.find(
1374
+ (c) => c.type === "BUY_X_PAY_Y" && c.isActive
1375
+ );
1376
+ const originalTotal = items.reduce((total, { product, variation, cartQuantity }) => {
1377
+ const priceInfo = getPriceInfo(product, variation);
1378
+ return total + priceInfo.effectivePrice * cartQuantity;
1379
+ }, 0);
1380
+ if (!_optionalChain([buyXPayYCampaign, 'optionalAccess', _13 => _13.BuyXPayYCampaign])) {
1381
+ const calculatedItems2 = items.map((item) => ({
1382
+ item,
1383
+ paidQuantity: item.cartQuantity,
1384
+ freeQuantity: 0,
1385
+ totalQuantity: item.cartQuantity
1386
+ }));
1387
+ const freeShipping2 = calculateFreeShipping(
1388
+ originalTotal,
1389
+ freeShippingCampaign
1390
+ );
1391
+ return {
1392
+ calculatedItems: calculatedItems2,
1393
+ cartTotal: originalTotal,
1394
+ originalTotal,
1395
+ totalSavings: 0,
1396
+ freeShipping: freeShipping2
1397
+ };
1398
+ }
1399
+ const { buyQuantity, payQuantity, applicableCategories } = buyXPayYCampaign.BuyXPayYCampaign;
1400
+ const applicableCategoryIds = new Set(
1401
+ applicableCategories.map((c) => c.id)
1402
+ );
1403
+ const eligibleUnits = items.flatMap((item) => {
1404
+ const { product, variation } = item;
1405
+ const itemCategories = _optionalChain([product, 'access', _14 => _14.categories, 'optionalAccess', _15 => _15.map, 'call', _16 => _16((cat) => cat.id)]) || [];
1406
+ const isEligible = itemCategories.some(
1407
+ (id) => applicableCategoryIds.has(id)
1408
+ );
1409
+ if (isEligible) {
1410
+ const priceInfo = getPriceInfo(product, variation);
1411
+ return Array.from({ length: item.cartQuantity }, () => ({
1412
+ price: priceInfo.effectivePrice,
1413
+ productId: product.id,
1414
+ variationId: _optionalChain([variation, 'optionalAccess', _17 => _17.id]),
1415
+ originalItem: item
1416
+ }));
1417
+ }
1418
+ return [];
1419
+ });
1420
+ if (eligibleUnits.length < buyQuantity) {
1421
+ const calculatedItems2 = items.map((item) => ({
1422
+ item,
1423
+ paidQuantity: item.cartQuantity,
1424
+ freeQuantity: 0,
1425
+ totalQuantity: item.cartQuantity
1426
+ }));
1427
+ const freeShipping2 = calculateFreeShipping(
1428
+ originalTotal,
1429
+ freeShippingCampaign
1430
+ );
1431
+ return {
1432
+ calculatedItems: calculatedItems2,
1433
+ cartTotal: originalTotal,
1434
+ originalTotal,
1435
+ totalSavings: 0,
1436
+ freeShipping: freeShipping2
1437
+ };
1438
+ }
1439
+ eligibleUnits.sort((a, b) => a.price - b.price);
1440
+ const numToMakeFree = buyQuantity - payQuantity;
1441
+ const itemsToMakeFree = eligibleUnits.slice(0, numToMakeFree);
1442
+ const totalSavings = itemsToMakeFree.reduce(
1443
+ (sum, item) => sum + item.price,
1444
+ 0
1445
+ );
1446
+ const freeCountMap = /* @__PURE__ */ new Map();
1447
+ for (const freebie of itemsToMakeFree) {
1448
+ const key = `${freebie.productId}${freebie.variationId ? `_${freebie.variationId}` : ""}`;
1449
+ freeCountMap.set(key, (freeCountMap.get(key) || 0) + 1);
1450
+ }
1451
+ const calculatedItems = items.map((item) => {
1452
+ const key = `${item.product.id}${_optionalChain([item, 'access', _18 => _18.variation, 'optionalAccess', _19 => _19.id]) ? `_${item.variation.id}` : ""}`;
1453
+ const freeQuantity = freeCountMap.get(key) || 0;
1454
+ const paidQuantity = item.cartQuantity - freeQuantity;
1455
+ return {
1456
+ item,
1457
+ paidQuantity: Math.max(0, paidQuantity),
1458
+ freeQuantity,
1459
+ totalQuantity: item.cartQuantity
1460
+ };
1461
+ });
1462
+ const cartTotal = originalTotal - totalSavings;
1463
+ const freeShipping = calculateFreeShipping(cartTotal, freeShippingCampaign);
1464
+ return {
1465
+ calculatedItems,
1466
+ cartTotal,
1467
+ originalTotal,
1468
+ totalSavings,
1469
+ freeShipping
1470
+ };
1471
+ }
1472
+ function calculateFreeShipping(cartTotal, campaign) {
1473
+ if (!_optionalChain([campaign, 'optionalAccess', _20 => _20.FreeShippingCampaign])) {
1474
+ return {
1475
+ isEligible: false,
1476
+ minimumSpend: 0,
1477
+ remainingAmount: 0
1478
+ };
1479
+ }
1480
+ const minimumSpend = campaign.FreeShippingCampaign.minimumSpend;
1481
+ const isEligible = cartTotal >= minimumSpend;
1482
+ const remainingAmount = isEligible ? 0 : minimumSpend - cartTotal;
1483
+ const eligibleShipmentMethodIds = _optionalChain([campaign, 'access', _21 => _21.FreeShippingCampaign, 'access', _22 => _22.shipmentMethods, 'optionalAccess', _23 => _23.map, 'call', _24 => _24(
1484
+ (method) => method.id
1485
+ )]);
1486
+ return {
1487
+ isEligible,
1488
+ minimumSpend,
1489
+ remainingAmount,
1490
+ campaignName: campaign.name,
1491
+ eligibleShipmentMethodIds
187
1492
  };
188
1493
  }
189
1494
 
@@ -193,5 +1498,8 @@ function createStorefrontClient(config) {
193
1498
 
194
1499
 
195
1500
 
196
- exports.AuthError = AuthError; exports.NotFoundError = NotFoundError; exports.RateLimitError = RateLimitError; exports.StorefrontError = StorefrontError; exports.ValidationError = ValidationError; exports.createStorefrontClient = createStorefrontClient;
1501
+
1502
+
1503
+
1504
+ exports.AuthError = AuthError; exports.NotFoundError = NotFoundError; exports.RateLimitError = RateLimitError; exports.StorefrontError = StorefrontError; exports.ValidationError = ValidationError; exports.calculateCartWithCampaigns = calculateCartWithCampaigns; exports.createStorefrontClient = createStorefrontClient; exports.getPriceInfo = getPriceInfo; exports.isSaleActive = isSaleActive;
197
1505
  //# sourceMappingURL=index.cjs.map