@behio/storefront-sdk 0.2.0 → 0.4.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.d.mts CHANGED
@@ -371,6 +371,51 @@ declare class BehioNetworkError extends Error {
371
371
  readonly isRetryable = true;
372
372
  constructor(message: string, isTimeout?: boolean);
373
373
  }
374
+ /**
375
+ * Shape every SDK call returns. Destructure `{data, error}` — exactly
376
+ * one of them is non-null on any given call. No more try/catch for
377
+ * expected failures; the type system forces you to handle `error`
378
+ * before touching `data`.
379
+ *
380
+ * const {data, error} = await behio.catalog.getProduct(slug);
381
+ * if (error) return <ErrorState code={error.code} />;
382
+ * return <ProductView product={data} />;
383
+ */
384
+ type SdkResult<T> = {
385
+ data: T;
386
+ error: null;
387
+ } | {
388
+ data: null;
389
+ error: SdkError;
390
+ };
391
+ /**
392
+ * Canonical error shape returned from every SDK call. Always carries a
393
+ * `code` you can branch on without parsing messages.
394
+ */
395
+ interface SdkError {
396
+ /**
397
+ * High-level category. `BehioErrorCode` covers API errors; additional
398
+ * buckets are network/timeout/abort/unknown.
399
+ */
400
+ code: BehioErrorCode;
401
+ /** Human-readable message (fallback for unknown codes / dev logging). */
402
+ message: string;
403
+ /** HTTP status, if the error came from the API. Null for network / abort. */
404
+ status: number | null;
405
+ /** Raw API body, if present. */
406
+ body?: unknown;
407
+ /** Whether the operation is safe to retry (true for 5xx / 429 / network). */
408
+ isRetryable: boolean;
409
+ /** Preserves the original thrown instance for stack traces + rethrows. */
410
+ cause?: unknown;
411
+ }
412
+ declare function ok<T>(data: T): SdkResult<T>;
413
+ declare function err<T = never>(error: SdkError): SdkResult<T>;
414
+ /**
415
+ * Converts any thrown value into a canonical SdkError. Used by the
416
+ * request wrapper when catching internal throws.
417
+ */
418
+ declare function toSdkError(err: unknown): SdkError;
374
419
  type BehioEventType = "auth:login" | "auth:logout" | "auth:token-refresh" | "auth:token-refresh-failed" | "cart:updated" | "cart:cleared" | "order:created" | "error" | "request" | "response" | "rate-limit-warning";
375
420
  type BehioEventHandler = (data?: unknown) => void;
376
421
  interface RequestInterceptorConfig {
@@ -571,10 +616,11 @@ declare class BehioStorefront {
571
616
  readonly returns: ReturnsModule;
572
617
  readonly consent: ConsentModule;
573
618
  readonly quotes: QuotesModule;
619
+ readonly addresses: AddressModule;
574
620
  /** Get basic shop info */
575
- getShopInfo(): Promise<ShopInfo>;
621
+ getShopInfo(): Promise<SdkResult<ShopInfo>>;
576
622
  /** Get SEO metadata for the shop homepage in the given locale (defaults to shop default). */
577
- getShopSeo(locale?: string): Promise<ShopSeo>;
623
+ getShopSeo(locale?: string): Promise<SdkResult<ShopSeo>>;
578
624
  /** Set auth tokens (e.g. from localStorage) */
579
625
  setTokens(tokens: {
580
626
  accessToken: string;
@@ -606,88 +652,99 @@ declare class BehioStorefront {
606
652
  reset: number | null;
607
653
  };
608
654
  private handleTokenRefresh;
609
- /** @internal */
655
+ /**
656
+ * Every public module method funnels through here. Internally calls
657
+ * `rawRequest` (which throws on failure) and maps thrown errors to
658
+ * `SdkError` so the public surface can return `SdkResult<T>`.
659
+ *
660
+ * @internal — don't call from outside the SDK; use the typed module
661
+ * methods (behio.catalog.*, behio.cart.*, …) instead.
662
+ */
610
663
  request<T>(method: string, path: string, options?: {
611
664
  body?: unknown;
612
665
  query?: Record<string, string | number | boolean | undefined | string[] | number[]>;
613
666
  auth?: boolean;
614
667
  signal?: AbortSignal;
615
- /** @internal Prevents infinite refresh loops */
616
- _isRetryAfterRefresh?: boolean;
617
- }): Promise<T>;
668
+ }): Promise<SdkResult<T>>;
669
+ /**
670
+ * Throws on failure (API error / network / timeout). Kept private so
671
+ * internal auth refresh recursion keeps its existing control flow —
672
+ * public callers must go through `request()` which returns Result.
673
+ */
674
+ private rawRequest;
618
675
  }
619
676
  declare class CatalogModule {
620
677
  private client;
621
678
  constructor(client: BehioStorefront);
622
679
  /** List products with filtering, pagination, search */
623
- getProducts(query?: ProductsQuery): Promise<PaginatedResponse<ProductListItem>>;
680
+ getProducts(query?: ProductsQuery): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
624
681
  /** Get product detail by slug */
625
682
  getProduct(slug: string, options?: {
626
683
  locale?: string;
627
684
  currency?: string;
628
- }): Promise<ProductDetail>;
685
+ }): Promise<SdkResult<ProductDetail>>;
629
686
  /** Get category tree */
630
- getCategories(locale?: string): Promise<{
687
+ getCategories(locale?: string): Promise<SdkResult<{
631
688
  categories: Category[];
632
- }>;
689
+ }>>;
633
690
  /** Get category detail by slug */
634
- getCategory(slug: string, locale?: string): Promise<CategoryDetail>;
691
+ getCategory(slug: string, locale?: string): Promise<SdkResult<CategoryDetail>>;
635
692
  /** Get products in a category */
636
- getCategoryProducts(slug: string, query?: ProductsQuery): Promise<PaginatedResponse<ProductListItem>>;
693
+ getCategoryProducts(slug: string, query?: ProductsQuery): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
637
694
  /** Get all labels */
638
- getLabels(locale?: string): Promise<{
695
+ getLabels(locale?: string): Promise<SdkResult<{
639
696
  labels: ProductLabel[];
640
- }>;
697
+ }>>;
641
698
  /** Get featured products */
642
699
  getFeatured(options?: {
643
700
  locale?: string;
644
701
  currency?: string;
645
- }): Promise<PaginatedResponse<ProductListItem>>;
702
+ }): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
646
703
  /** Get available filter fields for dynamic filter UI */
647
- getFilters(): Promise<{
704
+ getFilters(): Promise<SdkResult<{
648
705
  filters: FilterField[];
649
- }>;
706
+ }>>;
650
707
  /** Search products */
651
708
  search(query: string, options?: {
652
709
  page?: number;
653
710
  limit?: number;
654
- }): Promise<PaginatedResponse<ProductListItem>>;
711
+ }): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
655
712
  /** List all active bundles */
656
- getBundles(): Promise<{
713
+ getBundles(): Promise<SdkResult<{
657
714
  items: Bundle[];
658
- }>;
715
+ }>>;
659
716
  /** Get a single bundle by slug */
660
- getBundle(slug: string): Promise<Bundle>;
717
+ getBundle(slug: string): Promise<SdkResult<Bundle>>;
661
718
  /** Cross-sell / related / upsell products for a product */
662
- getCrossSell(productSlug: string): Promise<{
719
+ getCrossSell(productSlug: string): Promise<SdkResult<{
663
720
  related: CrossSellItem[];
664
721
  upsell: CrossSellItem[];
665
722
  crossSell: CrossSellItem[];
666
- }>;
723
+ }>>;
667
724
  /** Active promotions applicable to a product (with countdown end time) */
668
- getProductPromotions(productSlug: string): Promise<{
725
+ getProductPromotions(productSlug: string): Promise<SdkResult<{
669
726
  items: ActivePromotion[];
670
- }>;
727
+ }>>;
671
728
  /** Check a gift card code — returns validity and remaining balance */
672
- checkGiftCard(code: string): Promise<GiftCardBalance>;
729
+ checkGiftCard(code: string): Promise<SdkResult<GiftCardBalance>>;
673
730
  }
674
731
  declare class AuthModule {
675
732
  private client;
676
733
  constructor(client: BehioStorefront);
677
734
  /** Register a new customer */
678
- register(input: RegisterInput): Promise<AuthTokens>;
735
+ register(input: RegisterInput): Promise<SdkResult<AuthTokens>>;
679
736
  /** Login with email and password */
680
- login(input: LoginInput): Promise<AuthTokens>;
737
+ login(input: LoginInput): Promise<SdkResult<AuthTokens>>;
681
738
  /** Refresh access token using refresh token */
682
- refresh(refreshToken?: string): Promise<AuthTokens>;
739
+ refresh(refreshToken?: string): Promise<SdkResult<AuthTokens>>;
683
740
  /** Logout (invalidate refresh token) */
684
- logout(refreshToken?: string): Promise<MessageResponse>;
741
+ logout(refreshToken?: string): Promise<SdkResult<MessageResponse>>;
685
742
  /** Request password reset email */
686
- forgotPassword(email: string): Promise<MessageResponse>;
743
+ forgotPassword(email: string): Promise<SdkResult<MessageResponse>>;
687
744
  /** Reset password with token */
688
- resetPassword(token: string, newPassword: string): Promise<MessageResponse>;
745
+ resetPassword(token: string, newPassword: string): Promise<SdkResult<MessageResponse>>;
689
746
  /** Verify email with token */
690
- verifyEmail(token: string): Promise<MessageResponse>;
747
+ verifyEmail(token: string): Promise<SdkResult<MessageResponse>>;
691
748
  /** Check if user is logged in (has access token) */
692
749
  isLoggedIn(): boolean;
693
750
  }
@@ -695,39 +752,39 @@ declare class CartModule {
695
752
  private client;
696
753
  constructor(client: BehioStorefront);
697
754
  /** Get current cart */
698
- get(): Promise<Cart>;
755
+ get(): Promise<SdkResult<Cart>>;
699
756
  /** Add item to cart */
700
- addItem(input: AddToCartInput): Promise<Cart & {
757
+ addItem(input: AddToCartInput): Promise<SdkResult<Cart & {
701
758
  newSessionToken?: string;
702
- }>;
759
+ }>>;
703
760
  /** Update item quantity */
704
- updateQuantity(itemId: string, quantity: number): Promise<Cart>;
761
+ updateQuantity(itemId: string, quantity: number): Promise<SdkResult<Cart>>;
705
762
  /** Remove item from cart */
706
- removeItem(itemId: string): Promise<Cart>;
763
+ removeItem(itemId: string): Promise<SdkResult<Cart>>;
707
764
  /** Clear entire cart */
708
- clear(): Promise<void>;
765
+ clear(): Promise<SdkResult<void>>;
709
766
  /** Apply a gift card code to the cart. Balance is deducted at checkout. */
710
- applyGiftCard(code: string): Promise<Cart>;
767
+ applyGiftCard(code: string): Promise<SdkResult<Cart>>;
711
768
  /** Remove a gift card from the cart */
712
- removeGiftCard(): Promise<Cart>;
769
+ removeGiftCard(): Promise<SdkResult<Cart>>;
713
770
  /** Add a bundle to the cart (price is locked at the bundle's current price) */
714
- addBundle(bundleId: string, quantity?: number): Promise<Cart>;
771
+ addBundle(bundleId: string, quantity?: number): Promise<SdkResult<Cart>>;
715
772
  /** Update quantity of a bundle already in the cart */
716
- updateBundleQuantity(bundleId: string, quantity: number): Promise<Cart>;
773
+ updateBundleQuantity(bundleId: string, quantity: number): Promise<SdkResult<Cart>>;
717
774
  /** Remove a bundle from the cart */
718
- removeBundle(bundleId: string): Promise<Cart>;
775
+ removeBundle(bundleId: string): Promise<SdkResult<Cart>>;
719
776
  /** Merge anonymous cart into authenticated customer cart */
720
- merge(): Promise<Cart>;
777
+ merge(): Promise<SdkResult<Cart>>;
721
778
  /** Apply discount code */
722
- applyDiscount(code: string): Promise<Cart>;
779
+ applyDiscount(code: string): Promise<SdkResult<Cart>>;
723
780
  /** Remove discount code */
724
- removeDiscount(): Promise<Cart>;
781
+ removeDiscount(): Promise<SdkResult<Cart>>;
725
782
  }
726
783
  declare class CheckoutModule {
727
784
  private client;
728
785
  constructor(client: BehioStorefront);
729
786
  /** Create order from cart */
730
- createOrder(input: CheckoutInput): Promise<OrderDetail>;
787
+ createOrder(input: CheckoutInput): Promise<SdkResult<OrderDetail>>;
731
788
  }
732
789
  declare class OrdersModule {
733
790
  private client;
@@ -736,92 +793,122 @@ declare class OrdersModule {
736
793
  list(options?: {
737
794
  page?: number;
738
795
  limit?: number;
739
- }): Promise<PaginatedResponse<OrderListItem>>;
796
+ }): Promise<SdkResult<PaginatedResponse<OrderListItem>>>;
740
797
  /** Get order detail (requires auth) */
741
- get(orderNumber: string): Promise<OrderDetail>;
798
+ get(orderNumber: string): Promise<SdkResult<OrderDetail>>;
742
799
  /** Cancel a PENDING order (requires auth) */
743
- cancel(orderNumber: string): Promise<OrderDetail>;
800
+ cancel(orderNumber: string): Promise<SdkResult<OrderDetail>>;
744
801
  /** Track order by tracking token (no customer login required, only API key) */
745
- track(trackingToken: string): Promise<OrderDetail>;
802
+ track(trackingToken: string): Promise<SdkResult<OrderDetail>>;
746
803
  }
747
804
  declare class CustomerModule {
748
805
  private client;
749
806
  constructor(client: BehioStorefront);
750
807
  /** Get customer profile */
751
- getProfile(): Promise<CustomerProfile>;
808
+ getProfile(): Promise<SdkResult<CustomerProfile>>;
752
809
  /** Update customer profile */
753
- updateProfile(data: Partial<Pick<CustomerProfile, "firstName" | "lastName" | "phone">>): Promise<CustomerProfile>;
810
+ updateProfile(data: Partial<Pick<CustomerProfile, "firstName" | "lastName" | "phone">>): Promise<SdkResult<CustomerProfile>>;
754
811
  /** Change password */
755
- changePassword(currentPassword: string, newPassword: string): Promise<MessageResponse>;
812
+ changePassword(currentPassword: string, newPassword: string): Promise<SdkResult<MessageResponse>>;
756
813
  /** List addresses */
757
- getAddresses(): Promise<{
814
+ getAddresses(): Promise<SdkResult<{
758
815
  items: CustomerAddress[];
759
- }>;
816
+ }>>;
760
817
  /** Create address */
761
- createAddress(address: Omit<CustomerAddress, "id">): Promise<CustomerAddress>;
818
+ createAddress(address: Omit<CustomerAddress, "id">): Promise<SdkResult<CustomerAddress>>;
762
819
  /** Update address */
763
- updateAddress(addressId: string, data: Partial<CustomerAddress>): Promise<CustomerAddress>;
820
+ updateAddress(addressId: string, data: Partial<CustomerAddress>): Promise<SdkResult<CustomerAddress>>;
764
821
  /** Delete address */
765
- deleteAddress(addressId: string): Promise<void>;
822
+ deleteAddress(addressId: string): Promise<SdkResult<void>>;
766
823
  }
767
824
  declare class PagesModule {
768
825
  private client;
769
826
  constructor(client: BehioStorefront);
770
827
  /** List CMS pages */
771
- list(locale?: string): Promise<{
828
+ list(locale?: string): Promise<SdkResult<{
772
829
  pages: Page[];
773
- }>;
830
+ }>>;
774
831
  /** Get page by slug */
775
- get(slug: string, locale?: string): Promise<PageDetail>;
832
+ get(slug: string, locale?: string): Promise<SdkResult<PageDetail>>;
776
833
  }
777
834
  declare class WishlistModule {
778
835
  private client;
779
836
  constructor(client: BehioStorefront);
780
- get(): Promise<{
837
+ get(): Promise<SdkResult<{
781
838
  items: WishlistItem[];
782
- }>;
783
- add(productId: string): Promise<{
839
+ }>>;
840
+ add(productId: string): Promise<SdkResult<{
784
841
  success: boolean;
785
- }>;
786
- remove(productId: string): Promise<{
842
+ }>>;
843
+ remove(productId: string): Promise<SdkResult<{
787
844
  success: boolean;
788
- }>;
789
- isInWishlist(productId: string): Promise<{
845
+ }>>;
846
+ isInWishlist(productId: string): Promise<SdkResult<{
790
847
  inWishlist: boolean;
791
- }>;
848
+ }>>;
792
849
  }
793
850
  declare class ReviewsModule {
794
851
  private client;
795
852
  constructor(client: BehioStorefront);
796
- getProductReviews(productId: string, page?: number, limit?: number): Promise<ProductReviewsResponse>;
797
- submit(input: SubmitReviewInput): Promise<{
853
+ getProductReviews(productId: string, page?: number, limit?: number): Promise<SdkResult<ProductReviewsResponse>>;
854
+ submit(input: SubmitReviewInput): Promise<SdkResult<{
798
855
  id: string;
799
- }>;
800
- voteHelpful(reviewId: string, helpful: boolean): Promise<{
856
+ }>>;
857
+ voteHelpful(reviewId: string, helpful: boolean): Promise<SdkResult<{
801
858
  success: boolean;
802
- }>;
859
+ }>>;
803
860
  }
804
861
  declare class ReturnsModule {
805
862
  private client;
806
863
  constructor(client: BehioStorefront);
807
- submit(input: SubmitReturnInput): Promise<ReturnRequest>;
808
- getStatus(returnId: string, email: string): Promise<ReturnRequest>;
864
+ submit(input: SubmitReturnInput): Promise<SdkResult<ReturnRequest>>;
865
+ getStatus(returnId: string, email: string): Promise<SdkResult<ReturnRequest>>;
809
866
  }
810
867
  declare class ConsentModule {
811
868
  private client;
812
869
  constructor(client: BehioStorefront);
813
- record(input: CookieConsentInput): Promise<CookieConsent>;
814
- get(visitorId: string): Promise<CookieConsent | null>;
815
- revoke(visitorId: string): Promise<{
870
+ record(input: CookieConsentInput): Promise<SdkResult<CookieConsent>>;
871
+ get(visitorId: string): Promise<SdkResult<CookieConsent | null>>;
872
+ revoke(visitorId: string): Promise<SdkResult<{
816
873
  success: boolean;
817
- }>;
874
+ }>>;
818
875
  }
819
876
  declare class QuotesModule {
820
877
  private client;
821
878
  constructor(client: BehioStorefront);
822
- submit(input: SubmitQuoteInput): Promise<QuoteRequest>;
823
- accept(quoteId: string, email: string): Promise<QuoteRequest>;
824
- getStatus(quoteId: string): Promise<QuoteRequest>;
879
+ submit(input: SubmitQuoteInput): Promise<SdkResult<QuoteRequest>>;
880
+ accept(quoteId: string, email: string): Promise<SdkResult<QuoteRequest>>;
881
+ getStatus(quoteId: string): Promise<SdkResult<QuoteRequest>>;
882
+ }
883
+ interface AddressSuggestion {
884
+ placeId: string;
885
+ description: string;
886
+ street: string;
887
+ city: string;
888
+ zip: string;
889
+ country: string;
890
+ countryCode: string;
891
+ }
892
+ interface AddressDetail {
893
+ street: string;
894
+ streetNumber: string;
895
+ city: string;
896
+ zip: string;
897
+ country: string;
898
+ countryCode: string;
899
+ formattedAddress: string;
900
+ lat: number;
901
+ lng: number;
902
+ }
903
+ declare class AddressModule {
904
+ private client;
905
+ constructor(client: BehioStorefront);
906
+ /** Search for address suggestions (debounce on your side, or use the React hook) */
907
+ autocomplete(query: string, country: string): Promise<SdkResult<{
908
+ suggestions: AddressSuggestion[];
909
+ }>>;
910
+ /** Get full structured address from a suggestion's placeId */
911
+ getDetail(placeId: string): Promise<SdkResult<AddressDetail>>;
825
912
  }
826
913
 
827
- export { type ActivePromotion, type AddToCartInput, type AddressType, AddressTypes, type AuthTokens, BehioApiError, type BehioErrorCode, type BehioEventHandler, type BehioEventType, BehioNetworkError, BehioStorefront, type BehioStorefrontConfig, type Bundle, type BundleItem, type Cart, type CartDiscount, type CartItem, type CartItemProduct, type Category, type CategoryDetail, type CheckoutAddress, type CheckoutInput, type CookieConsent, type CookieConsentInput, type CrossSellItem, type CustomerAddress, type CustomerProfile, type DataGroupFieldType, type FilterField, type FulfillmentStatus, FulfillmentStatuses, type GiftCardBalance, type LoginInput, type MessageResponse, type OrderDetail, type OrderItem, type OrderListItem, type OrderStatus, type OrderStatusHistory, OrderStatuses, type Page, type PageDetail, type PaginatedResponse, type PaymentStatus, PaymentStatuses, type ProductDetail, type ProductLabel, type ProductListItem, type ProductPrice, type ProductReview, type ProductReviewsResponse, ProductSort, type ProductSortValue, type ProductVariant, type ProductVolumePrice, type ProductsQuery, type QuoteRequest, type RegisterInput, type RequestInterceptor, type RequestInterceptorConfig, type ResponseInterceptor, type ResponseInterceptorData, type ReturnRequest, type ShopInfo, type ShopSeo, type SubmitQuoteInput, type SubmitReturnInput, type SubmitReviewInput, type WishlistItem };
914
+ export { type ActivePromotion, type AddToCartInput, type AddressDetail, type AddressSuggestion, type AddressType, AddressTypes, type AuthTokens, BehioApiError, type BehioErrorCode, type BehioEventHandler, type BehioEventType, BehioNetworkError, BehioStorefront, type BehioStorefrontConfig, type Bundle, type BundleItem, type Cart, type CartDiscount, type CartItem, type CartItemProduct, type Category, type CategoryDetail, type CheckoutAddress, type CheckoutInput, type CookieConsent, type CookieConsentInput, type CrossSellItem, type CustomerAddress, type CustomerProfile, type DataGroupFieldType, type FilterField, type FulfillmentStatus, FulfillmentStatuses, type GiftCardBalance, type LoginInput, type MessageResponse, type OrderDetail, type OrderItem, type OrderListItem, type OrderStatus, type OrderStatusHistory, OrderStatuses, type Page, type PageDetail, type PaginatedResponse, type PaymentStatus, PaymentStatuses, type ProductDetail, type ProductLabel, type ProductListItem, type ProductPrice, type ProductReview, type ProductReviewsResponse, ProductSort, type ProductSortValue, type ProductVariant, type ProductVolumePrice, type ProductsQuery, type QuoteRequest, type RegisterInput, type RequestInterceptor, type RequestInterceptorConfig, type ResponseInterceptor, type ResponseInterceptorData, type ReturnRequest, type SdkError, type SdkResult, type ShopInfo, type ShopSeo, type SubmitQuoteInput, type SubmitReturnInput, type SubmitReviewInput, type WishlistItem, err, ok, toSdkError };