@putiikkipalvelu/storefront-sdk 0.2.2 → 0.2.4

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.d.ts CHANGED
@@ -91,7 +91,7 @@ interface FeatureFlags {
91
91
  reviewsEnabled: boolean;
92
92
  }
93
93
  /** Campaign type */
94
- type CampaignType = "FREE_SHIPPING" | "BUY_X_PAY_Y";
94
+ type CampaignType = "BUY_X_PAY_Y";
95
95
  /**
96
96
  * Store campaign (promotion)
97
97
  */
@@ -116,24 +116,9 @@ interface Campaign {
116
116
  createdAt: string;
117
117
  /** Last update timestamp (ISO 8601) */
118
118
  updatedAt: string;
119
- /** Free shipping campaign details (if type is FREE_SHIPPING) */
120
- FreeShippingCampaign: FreeShippingCampaign | null;
121
119
  /** Buy X Pay Y campaign details (if type is BUY_X_PAY_Y) */
122
120
  BuyXPayYCampaign: BuyXPayYCampaign | null;
123
121
  }
124
- /**
125
- * Free shipping campaign details
126
- */
127
- interface FreeShippingCampaign {
128
- /** Unique identifier */
129
- id: string;
130
- /** Parent campaign ID */
131
- campaignId: string;
132
- /** Minimum spend in cents to qualify for free shipping */
133
- minimumSpend: number;
134
- /** Shipping methods eligible for free shipping */
135
- shipmentMethods: ShipmentMethod[];
136
- }
137
122
  /**
138
123
  * Buy X Pay Y campaign details (e.g., "Buy 3, Pay 2")
139
124
  */
@@ -152,18 +137,19 @@ interface BuyXPayYCampaign {
152
137
  /**
153
138
  * Shipit shipping method details
154
139
  * Represents a shipping service synced from the Shipit API
140
+ * Supports multiple carriers in a single method for multi-carrier shipping
155
141
  */
156
142
  interface ShipitShippingMethod {
157
143
  /** Unique ID */
158
144
  id: string;
159
- /** Shipit service identifier */
160
- serviceId: string;
145
+ /** Shipit service identifiers for all selected carriers */
146
+ serviceIds: string[];
161
147
  /** Service name */
162
148
  name: string;
163
- /** Carrier name (e.g., "Posti", "Matkahuolto") */
164
- carrier: string;
165
- /** Carrier logo URL */
166
- logo: string;
149
+ /** Carrier names (e.g., ["Posti", "Matkahuolto"]) */
150
+ carriers: string[];
151
+ /** Carrier logo URLs */
152
+ logos: string[];
167
153
  /** Whether pickup is included */
168
154
  pickUpIncluded: boolean;
169
155
  /** Whether home delivery is available */
@@ -184,16 +170,16 @@ interface ShipitShippingMethod {
184
170
  length: number;
185
171
  /** Package width in cm */
186
172
  width: number;
187
- /** Package weight in kg */
173
+ /** Package weight in kg @deprecated Use maxWeight instead */
188
174
  weight: number;
175
+ /** Maximum package weight in kg for this shipping tier */
176
+ maxWeight: number;
189
177
  /** Service type */
190
178
  type: string;
191
179
  /** Shipit price in cents */
192
180
  price: number;
193
- /** Whether pickup point selection is available */
194
- pickupPoint: boolean;
195
- /** Whether only parcel locker delivery is available */
196
- onlyParchelLocker: boolean;
181
+ /** Whether to show pickup point selector (true) or home delivery only (false) */
182
+ showPickupPoints: boolean;
197
183
  /** Reference to parent shipment method */
198
184
  shipmentMethodId: string;
199
185
  /** Created timestamp */
@@ -275,6 +261,8 @@ interface ProductVariationListing {
275
261
  * Full product variation (for product detail page)
276
262
  */
277
263
  interface ProductVariation extends ProductVariationListing {
264
+ /** Variation weight in kg (null = use product weight) */
265
+ weight: number | null;
278
266
  /** Available quantity (null = unlimited) */
279
267
  quantity: number | null;
280
268
  /** Stock keeping unit */
@@ -323,6 +311,8 @@ interface Product {
323
311
  * Used by: /product/{slug}
324
312
  */
325
313
  interface ProductDetail extends Omit<Product, "variations"> {
314
+ /** Product weight in kg (for shipping calculations) */
315
+ weight: number;
326
316
  /** Stock keeping unit */
327
317
  sku: string | null;
328
318
  /** SEO meta title */
@@ -1699,6 +1689,13 @@ type CartResource = ReturnType<typeof createCartResource>;
1699
1689
  * Methods for fetching shipment methods and pickup locations.
1700
1690
  */
1701
1691
 
1692
+ /**
1693
+ * Options for fetching shipment methods with weight-based filtering
1694
+ */
1695
+ interface GetMethodsOptions extends FetchOptions {
1696
+ /** Cart items - weight will be calculated automatically */
1697
+ cartItems?: CartItem[];
1698
+ }
1702
1699
  /**
1703
1700
  * Shipping resource for fetching shipment methods and pickup locations
1704
1701
  */
@@ -1707,7 +1704,7 @@ declare function createShippingResource(fetcher: Fetcher): {
1707
1704
  * Get all available shipment methods for the store.
1708
1705
  * Returns methods without pickup locations - use `getWithLocations` for postal code specific data.
1709
1706
  *
1710
- * @param options - Fetch options (caching, headers, etc.)
1707
+ * @param options - Fetch options including optional cartItems for weight-based filtering
1711
1708
  * @returns Available shipment methods
1712
1709
  *
1713
1710
  * @example
@@ -1718,14 +1715,22 @@ declare function createShippingResource(fetcher: Fetcher): {
1718
1715
  * console.log(`${method.name}: ${method.price / 100}€`);
1719
1716
  * });
1720
1717
  * ```
1718
+ *
1719
+ * @example Weight-based filtering
1720
+ * ```typescript
1721
+ * // Pass cart items - SDK calculates weight automatically
1722
+ * const { shipmentMethods } = await client.shipping.getMethods({
1723
+ * cartItems: cartItems
1724
+ * });
1725
+ * ```
1721
1726
  */
1722
- getMethods(options?: FetchOptions): Promise<ShipmentMethodsResponse>;
1727
+ getMethods(options?: GetMethodsOptions): Promise<ShipmentMethodsResponse>;
1723
1728
  /**
1724
1729
  * Get shipment methods with pickup locations for a specific postal code.
1725
1730
  * Calls the Shipit API to fetch nearby pickup points (parcel lockers, etc.)
1726
1731
  *
1727
1732
  * @param postalCode - Customer's postal code (e.g., "00100")
1728
- * @param options - Fetch options (caching, headers, etc.)
1733
+ * @param options - Fetch options including optional cartItems for weight-based filtering
1729
1734
  * @returns Shipment methods and nearby pickup locations with pricing
1730
1735
  *
1731
1736
  * @example
@@ -1741,16 +1746,17 @@ declare function createShippingResource(fetcher: Fetcher): {
1741
1746
  * });
1742
1747
  * ```
1743
1748
  *
1744
- * @example Filter by carrier
1749
+ * @example Weight-based filtering with postal code
1745
1750
  * ```typescript
1746
- * const { pricedLocations } = await client.shipping.getWithLocations("00100");
1747
- *
1748
- * const postiLocations = pricedLocations.filter(
1749
- * loc => loc.carrier === "Posti"
1751
+ * const { shipmentMethods, pricedLocations } = await client.shipping.getWithLocations(
1752
+ * "00100",
1753
+ * { cartItems: cartItems }
1750
1754
  * );
1755
+ *
1756
+ * // Only shows methods that support the cart's total weight
1751
1757
  * ```
1752
1758
  */
1753
- getWithLocations(postalCode: string, options?: FetchOptions): Promise<ShipmentMethodsWithLocationsResponse>;
1759
+ getWithLocations(postalCode: string, options?: GetMethodsOptions): Promise<ShipmentMethodsWithLocationsResponse>;
1754
1760
  };
1755
1761
  /**
1756
1762
  * Type for the shipping resource
@@ -2466,4 +2472,4 @@ declare class VerificationRequiredError extends StorefrontError {
2466
2472
  constructor(message: string, customerId: string);
2467
2473
  }
2468
2474
 
2469
- export { type AddToCartParams, type AddToWishlistResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type FreeShippingCampaign, type FreeShippingStatus, type GetOrdersResponse, type GetUserResponse, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, NotFoundError, type Order, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupLocation, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductVariation, type ProductVariationListing, RateLimitError, type RegisterData, type RegisterResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type ShipmentMethodsWithLocationsResponse, type StoreConfig, type StoreInfo, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, calculateCartWithCampaigns, createStorefrontClient, getPriceInfo, isSaleActive };
2475
+ export { type AddToCartParams, type AddToWishlistResponse, AuthError, type BuyXPayYCampaign, type CalculatedCartItem, type Campaign, type CampaignType, type CartCalculationResult, type CartItem, type CartResponse, type CartSessionOptions, type CartValidationChanges, type CartValidationResponse, type Category, type CategoryReference, type CategoryResponse, type CheckoutCustomerData, type CheckoutErrorCode, type CheckoutErrorDetails, type CheckoutOptions, type CheckoutParams, type CheckoutShipmentMethod, type ConfirmationItemType, type ConfirmationOrderCustomerData, type ConfirmationOrderLineItem, type ConfirmationOrderShipmentMethod, type Customer, type CustomerOrder, type DeleteAccountResponse, type FeatureFlags, type FetchOptions, type ForgotPasswordResponse, type FreeShippingStatus, type GetOrdersResponse, type GetUserResponse, type LoginOptions, type LoginResponse, type LoginVerificationRequiredResponse, type LogoutResponse, NotFoundError, type Order, type OrderLineItem, type OrderProductInfo, type OrderShipmentMethod, type OrderStatus, type PaymentConfig, type PaytrailCheckoutResponse, type PaytrailGroup, type PaytrailProvider, type PickupLocation, type PriceInfo, type Product, type ProductCountResponse, type ProductDetail, type ProductListParams, type ProductListResponse, type ProductSortOption, type ProductVariation, type ProductVariationListing, RateLimitError, type RegisterData, type RegisterResponse, type RemoveFromCartParams, type RemoveFromWishlistResponse, type ResendVerificationResponse, type ResetPasswordResponse, type ShipitShippingMethod, type ShipmentMethod, type ShipmentMethodsResponse, type ShipmentMethodsWithLocationsResponse, type StoreConfig, type StoreInfo, type StoreSeo, type StorefrontClient, type StorefrontClientConfig, StorefrontError, type StripeCheckoutResponse, type UpdateCartQuantityParams, type UpdateProfileData, type UpdateProfileResponse, ValidationError, type VariationOption, VerificationRequiredError, type VerifyEmailResponse, type WishlistItem, type WishlistProduct, type WishlistResponse, type WishlistVariation, type WishlistVariationOption, calculateCartWithCampaigns, createStorefrontClient, getPriceInfo, isSaleActive };
package/dist/index.js CHANGED
@@ -611,13 +611,19 @@ function createCartResource(fetcher) {
611
611
  }
612
612
 
613
613
  // src/resources/shipping.ts
614
+ function calculateCartWeight(items) {
615
+ return items.reduce((total, item) => {
616
+ const itemWeight = item.variation?.weight ?? item.product.weight ?? 0.5;
617
+ return total + itemWeight * item.cartQuantity;
618
+ }, 0);
619
+ }
614
620
  function createShippingResource(fetcher) {
615
621
  return {
616
622
  /**
617
623
  * Get all available shipment methods for the store.
618
624
  * Returns methods without pickup locations - use `getWithLocations` for postal code specific data.
619
625
  *
620
- * @param options - Fetch options (caching, headers, etc.)
626
+ * @param options - Fetch options including optional cartItems for weight-based filtering
621
627
  * @returns Available shipment methods
622
628
  *
623
629
  * @example
@@ -628,22 +634,34 @@ function createShippingResource(fetcher) {
628
634
  * console.log(`${method.name}: ${method.price / 100}€`);
629
635
  * });
630
636
  * ```
637
+ *
638
+ * @example Weight-based filtering
639
+ * ```typescript
640
+ * // Pass cart items - SDK calculates weight automatically
641
+ * const { shipmentMethods } = await client.shipping.getMethods({
642
+ * cartItems: cartItems
643
+ * });
644
+ * ```
631
645
  */
632
646
  async getMethods(options) {
633
- return fetcher.request(
634
- "/api/storefront/v1/shipment-methods",
635
- {
636
- method: "GET",
637
- ...options
638
- }
639
- );
647
+ const params = new URLSearchParams();
648
+ if (options?.cartItems?.length) {
649
+ const cartWeight = calculateCartWeight(options.cartItems);
650
+ params.set("cartWeight", cartWeight.toString());
651
+ }
652
+ const queryString = params.toString();
653
+ const url = `/api/storefront/v1/shipment-methods${queryString ? `?${queryString}` : ""}`;
654
+ return fetcher.request(url, {
655
+ method: "GET",
656
+ ...options
657
+ });
640
658
  },
641
659
  /**
642
660
  * Get shipment methods with pickup locations for a specific postal code.
643
661
  * Calls the Shipit API to fetch nearby pickup points (parcel lockers, etc.)
644
662
  *
645
663
  * @param postalCode - Customer's postal code (e.g., "00100")
646
- * @param options - Fetch options (caching, headers, etc.)
664
+ * @param options - Fetch options including optional cartItems for weight-based filtering
647
665
  * @returns Shipment methods and nearby pickup locations with pricing
648
666
  *
649
667
  * @example
@@ -659,23 +677,28 @@ function createShippingResource(fetcher) {
659
677
  * });
660
678
  * ```
661
679
  *
662
- * @example Filter by carrier
680
+ * @example Weight-based filtering with postal code
663
681
  * ```typescript
664
- * const { pricedLocations } = await client.shipping.getWithLocations("00100");
665
- *
666
- * const postiLocations = pricedLocations.filter(
667
- * loc => loc.carrier === "Posti"
682
+ * const { shipmentMethods, pricedLocations } = await client.shipping.getWithLocations(
683
+ * "00100",
684
+ * { cartItems: cartItems }
668
685
  * );
686
+ *
687
+ * // Only shows methods that support the cart's total weight
669
688
  * ```
670
689
  */
671
690
  async getWithLocations(postalCode, options) {
672
- return fetcher.request(
673
- `/api/storefront/v1/shipment-methods/${encodeURIComponent(postalCode)}`,
674
- {
675
- method: "GET",
676
- ...options
677
- }
678
- );
691
+ const params = new URLSearchParams();
692
+ if (options?.cartItems?.length) {
693
+ const cartWeight = calculateCartWeight(options.cartItems);
694
+ params.set("cartWeight", cartWeight.toString());
695
+ }
696
+ const queryString = params.toString();
697
+ const url = `/api/storefront/v1/shipment-methods/${encodeURIComponent(postalCode)}${queryString ? `?${queryString}` : ""}`;
698
+ return fetcher.request(url, {
699
+ method: "GET",
700
+ ...options
701
+ });
679
702
  }
680
703
  };
681
704
  }
@@ -1448,9 +1471,6 @@ function getPriceInfo(product, variation) {
1448
1471
 
1449
1472
  // src/utils/cart-calculations.ts
1450
1473
  function calculateCartWithCampaigns(items, campaigns) {
1451
- const freeShippingCampaign = campaigns.find(
1452
- (c) => c.type === "FREE_SHIPPING" && c.isActive
1453
- );
1454
1474
  const buyXPayYCampaign = campaigns.find(
1455
1475
  (c) => c.type === "BUY_X_PAY_Y" && c.isActive
1456
1476
  );
@@ -1458,6 +1478,11 @@ function calculateCartWithCampaigns(items, campaigns) {
1458
1478
  const priceInfo = getPriceInfo(product, variation);
1459
1479
  return total + priceInfo.effectivePrice * cartQuantity;
1460
1480
  }, 0);
1481
+ const freeShipping = {
1482
+ isEligible: false,
1483
+ minimumSpend: 0,
1484
+ remainingAmount: 0
1485
+ };
1461
1486
  if (!buyXPayYCampaign?.BuyXPayYCampaign) {
1462
1487
  const calculatedItems2 = items.map((item) => ({
1463
1488
  item,
@@ -1465,16 +1490,12 @@ function calculateCartWithCampaigns(items, campaigns) {
1465
1490
  freeQuantity: 0,
1466
1491
  totalQuantity: item.cartQuantity
1467
1492
  }));
1468
- const freeShipping2 = calculateFreeShipping(
1469
- originalTotal,
1470
- freeShippingCampaign
1471
- );
1472
1493
  return {
1473
1494
  calculatedItems: calculatedItems2,
1474
1495
  cartTotal: originalTotal,
1475
1496
  originalTotal,
1476
1497
  totalSavings: 0,
1477
- freeShipping: freeShipping2
1498
+ freeShipping
1478
1499
  };
1479
1500
  }
1480
1501
  const { buyQuantity, payQuantity, applicableCategories } = buyXPayYCampaign.BuyXPayYCampaign;
@@ -1505,16 +1526,12 @@ function calculateCartWithCampaigns(items, campaigns) {
1505
1526
  freeQuantity: 0,
1506
1527
  totalQuantity: item.cartQuantity
1507
1528
  }));
1508
- const freeShipping2 = calculateFreeShipping(
1509
- originalTotal,
1510
- freeShippingCampaign
1511
- );
1512
1529
  return {
1513
1530
  calculatedItems: calculatedItems2,
1514
1531
  cartTotal: originalTotal,
1515
1532
  originalTotal,
1516
1533
  totalSavings: 0,
1517
- freeShipping: freeShipping2
1534
+ freeShipping
1518
1535
  };
1519
1536
  }
1520
1537
  eligibleUnits.sort((a, b) => a.price - b.price);
@@ -1541,7 +1558,6 @@ function calculateCartWithCampaigns(items, campaigns) {
1541
1558
  };
1542
1559
  });
1543
1560
  const cartTotal = originalTotal - totalSavings;
1544
- const freeShipping = calculateFreeShipping(cartTotal, freeShippingCampaign);
1545
1561
  return {
1546
1562
  calculatedItems,
1547
1563
  cartTotal,
@@ -1550,28 +1566,6 @@ function calculateCartWithCampaigns(items, campaigns) {
1550
1566
  freeShipping
1551
1567
  };
1552
1568
  }
1553
- function calculateFreeShipping(cartTotal, campaign) {
1554
- if (!campaign?.FreeShippingCampaign) {
1555
- return {
1556
- isEligible: false,
1557
- minimumSpend: 0,
1558
- remainingAmount: 0
1559
- };
1560
- }
1561
- const minimumSpend = campaign.FreeShippingCampaign.minimumSpend;
1562
- const isEligible = cartTotal >= minimumSpend;
1563
- const remainingAmount = isEligible ? 0 : minimumSpend - cartTotal;
1564
- const eligibleShipmentMethodIds = campaign.FreeShippingCampaign.shipmentMethods?.map(
1565
- (method) => method.id
1566
- );
1567
- return {
1568
- isEligible,
1569
- minimumSpend,
1570
- remainingAmount,
1571
- campaignName: campaign.name,
1572
- eligibleShipmentMethodIds
1573
- };
1574
- }
1575
1569
  export {
1576
1570
  AuthError,
1577
1571
  NotFoundError,