@misiki/gocommerce-connector 0.12.0 → 0.14.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.
@@ -201,6 +201,10 @@ type Product = {
201
201
  seo_description: string;
202
202
  image_url?: string;
203
203
  media_count?: number;
204
+ /** The gallery, pictures and videos in order: on the public product only (D134). */
205
+ media?: VariantImage[];
206
+ /** The sold count rounded down; absent unless the shop shows counts and it passed the threshold (D134). */
207
+ sold_at_least?: number;
204
208
  options: ProductOption[] | null;
205
209
  variants: Variant[] | null;
206
210
  collections: {
@@ -574,6 +578,8 @@ type SearchResult = {
574
578
  total: number;
575
579
  limit: number;
576
580
  offset: number;
581
+ /** Meilisearch did not answer: search the product listing instead. */
582
+ unavailable?: boolean;
577
583
  };
578
584
  /** One approved vendor's offer on a variant, from `GET /api/variants/{id}/offers`. Cheapest first. */
579
585
  type Offer = {
@@ -589,6 +595,14 @@ type MenuSummary = {
589
595
  handle: string;
590
596
  title: string;
591
597
  };
598
+ /** GET /api/postcodes/{country}/{code} (D134). */
599
+ type Postcode = {
600
+ country: string;
601
+ postcode: string;
602
+ city: string;
603
+ state: string;
604
+ state_code: string;
605
+ };
592
606
 
593
607
  /**
594
608
  * The state this connector keeps in the shopper's browser, and only there.
@@ -650,11 +664,16 @@ type CartExtras = {
650
664
  };
651
665
 
652
666
  /**
653
- * Every picture the public API offers for a product: the lead image, then each
654
- * variant's. The engine keeps the full gallery on admin routes only, so this
655
- * is the honest union rather than the whole media library.
667
+ * Every picture the public API offers for a product: the lead image, the
668
+ * product's gallery (on the single product, D134), then each variant's.
656
669
  */
657
670
  declare function productImages(p: Product): string[];
671
+ /**
672
+ * The product's videos, an upload or a YouTube link, in the gallery's order
673
+ * (D134). They follow the pictures in `images`, where the storefront's gallery
674
+ * plays them; a card's thumbnail is never one.
675
+ */
676
+ declare function productVideos(p: Product): string[];
658
677
  declare function toVariant(v: Variant, p: Product, optionless: boolean): {
659
678
  id: string;
660
679
  productId: string;
@@ -711,6 +730,10 @@ declare function toProduct(p: Product, extra?: {
711
730
  image_url: string;
712
731
  images: string;
713
732
  imageList: string[];
733
+ videos: string[];
734
+ highlights: string[];
735
+ freeGift: string | null;
736
+ soldAtLeast: number | null;
714
737
  manageInventory: boolean;
715
738
  allowBackorder: boolean;
716
739
  stock: number;
@@ -1468,6 +1491,19 @@ type CatalogPage = {
1468
1491
  declare class CatalogService extends BaseService {
1469
1492
  protected readonly facts: StoreFacts;
1470
1493
  protected queryCatalog(q: CatalogQuery): Promise<CatalogPage>;
1494
+ /**
1495
+ * The shelf from the Meilisearch module, or null when the store has it off,
1496
+ * sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
1497
+ * the caller asks the database instead of showing the shopper an error.
1498
+ */
1499
+ protected fromIndex(q: CatalogQuery, o: {
1500
+ page: number;
1501
+ limit: number;
1502
+ search?: string;
1503
+ sortKey?: string;
1504
+ wantsRange: boolean;
1505
+ hierarchy: CatalogPage['categoryHierarchy'];
1506
+ }): Promise<CatalogPage | null>;
1471
1507
  }
1472
1508
 
1473
1509
  /**
@@ -1511,6 +1547,10 @@ declare class ProductService extends CatalogService {
1511
1547
  image_url: string;
1512
1548
  images: string;
1513
1549
  imageList: string[];
1550
+ videos: string[];
1551
+ highlights: string[];
1552
+ freeGift: string | null;
1553
+ soldAtLeast: number | null;
1514
1554
  manageInventory: boolean;
1515
1555
  allowBackorder: boolean;
1516
1556
  stock: number;
@@ -1624,6 +1664,10 @@ declare class ProductService extends CatalogService {
1624
1664
  image_url: string;
1625
1665
  images: string;
1626
1666
  imageList: string[];
1667
+ videos: string[];
1668
+ highlights: string[];
1669
+ freeGift: string | null;
1670
+ soldAtLeast: number | null;
1627
1671
  manageInventory: boolean;
1628
1672
  allowBackorder: boolean;
1629
1673
  stock: number;
@@ -1772,6 +1816,10 @@ declare class ProductService extends CatalogService {
1772
1816
  image_url: string;
1773
1817
  images: string;
1774
1818
  imageList: string[];
1819
+ videos: string[];
1820
+ highlights: string[];
1821
+ freeGift: string | null;
1822
+ soldAtLeast: number | null;
1775
1823
  manageInventory: boolean;
1776
1824
  allowBackorder: boolean;
1777
1825
  stock: number;
@@ -1919,6 +1967,10 @@ declare class ProductService extends CatalogService {
1919
1967
  image_url: string;
1920
1968
  images: string;
1921
1969
  imageList: string[];
1970
+ videos: string[];
1971
+ highlights: string[];
1972
+ freeGift: string | null;
1973
+ soldAtLeast: number | null;
1922
1974
  manageInventory: boolean;
1923
1975
  allowBackorder: boolean;
1924
1976
  stock: number;
@@ -2113,6 +2165,10 @@ declare class ProductService extends CatalogService {
2113
2165
  image_url: string;
2114
2166
  images: string;
2115
2167
  imageList: string[];
2168
+ videos: string[];
2169
+ highlights: string[];
2170
+ freeGift: string | null;
2171
+ soldAtLeast: number | null;
2116
2172
  manageInventory: boolean;
2117
2173
  allowBackorder: boolean;
2118
2174
  stock: number;
@@ -2333,6 +2389,10 @@ declare class SearchService extends CatalogService {
2333
2389
  image_url: string;
2334
2390
  images: string;
2335
2391
  imageList: string[];
2392
+ videos: string[];
2393
+ highlights: string[];
2394
+ freeGift: string | null;
2395
+ soldAtLeast: number | null;
2336
2396
  manageInventory: boolean;
2337
2397
  allowBackorder: boolean;
2338
2398
  stock: number;
@@ -2518,6 +2578,10 @@ declare class MeilisearchService extends CatalogService {
2518
2578
  image_url: string;
2519
2579
  images: string;
2520
2580
  imageList: string[];
2581
+ videos: string[];
2582
+ highlights: string[];
2583
+ freeGift: string | null;
2584
+ soldAtLeast: number | null;
2521
2585
  manageInventory: boolean;
2522
2586
  allowBackorder: boolean;
2523
2587
  stock: number;
@@ -2648,39 +2712,6 @@ declare class MeilisearchService extends CatalogService {
2648
2712
  search?: string;
2649
2713
  limit?: number;
2650
2714
  }): Promise<{
2651
- data: {
2652
- id: string;
2653
- slug: string;
2654
- title: string;
2655
- name: string;
2656
- description: string;
2657
- currency: string;
2658
- price: number;
2659
- mrp: number;
2660
- minPrice: number;
2661
- maxPrice: number;
2662
- thumbnail: string | null;
2663
- image_url: string | null;
2664
- images: string;
2665
- stock: number;
2666
- hasStock: boolean;
2667
- manageInventory: boolean;
2668
- allowBackorder: boolean;
2669
- productTags: string;
2670
- category: {
2671
- name: string;
2672
- slug: string;
2673
- } | null;
2674
- vendor: {
2675
- businessName: string;
2676
- } | null;
2677
- variants: ReturnType<typeof toVariant>[];
2678
- options: never[];
2679
- ratings: never[];
2680
- link: string;
2681
- updatedAt: string;
2682
- }[];
2683
- } | {
2684
2715
  data: {
2685
2716
  id: string;
2686
2717
  slug: string;
@@ -2705,6 +2736,10 @@ declare class MeilisearchService extends CatalogService {
2705
2736
  image_url: string;
2706
2737
  images: string;
2707
2738
  imageList: string[];
2739
+ videos: string[];
2740
+ highlights: string[];
2741
+ freeGift: string | null;
2742
+ soldAtLeast: number | null;
2708
2743
  manageInventory: boolean;
2709
2744
  allowBackorder: boolean;
2710
2745
  stock: number;
@@ -2787,6 +2822,37 @@ declare class MeilisearchService extends CatalogService {
2787
2822
  metadata: Record<string, unknown> | null;
2788
2823
  createdAt: string;
2789
2824
  updatedAt: string;
2825
+ }[] | {
2826
+ id: string;
2827
+ slug: string;
2828
+ title: string;
2829
+ name: string;
2830
+ description: string;
2831
+ currency: string;
2832
+ price: number;
2833
+ mrp: number;
2834
+ minPrice: number;
2835
+ maxPrice: number;
2836
+ thumbnail: string | null;
2837
+ image_url: string | null;
2838
+ images: string;
2839
+ stock: number;
2840
+ hasStock: boolean;
2841
+ manageInventory: boolean;
2842
+ allowBackorder: boolean;
2843
+ productTags: string;
2844
+ category: {
2845
+ name: string;
2846
+ slug: string;
2847
+ } | null;
2848
+ vendor: {
2849
+ businessName: string;
2850
+ } | null;
2851
+ variants: ReturnType<typeof toVariant>[];
2852
+ options: never[];
2853
+ ratings: never[];
2854
+ link: string;
2855
+ updatedAt: string;
2790
2856
  }[];
2791
2857
  }>;
2792
2858
  }
@@ -2894,6 +2960,10 @@ declare class CollectionService extends BaseService {
2894
2960
  image_url: string;
2895
2961
  images: string;
2896
2962
  imageList: string[];
2963
+ videos: string[];
2964
+ highlights: string[];
2965
+ freeGift: string | null;
2966
+ soldAtLeast: number | null;
2897
2967
  manageInventory: boolean;
2898
2968
  allowBackorder: boolean;
2899
2969
  stock: number;
@@ -3002,6 +3072,10 @@ declare class CollectionService extends BaseService {
3002
3072
  image_url: string;
3003
3073
  images: string;
3004
3074
  imageList: string[];
3075
+ videos: string[];
3076
+ highlights: string[];
3077
+ freeGift: string | null;
3078
+ soldAtLeast: number | null;
3005
3079
  manageInventory: boolean;
3006
3080
  allowBackorder: boolean;
3007
3081
  stock: number;
@@ -5779,6 +5853,22 @@ declare class AddressService extends BaseService {
5779
5853
  createdAt: string;
5780
5854
  updatedAt: string;
5781
5855
  }>;
5856
+ /**
5857
+ * The city and state for a postcode (D134), for the address form to fill
5858
+ * in. India's six-digit PIN codes only, from the directory the engine was
5859
+ * given; null for anything it cannot answer, so the form simply leaves the
5860
+ * fields to the shopper.
5861
+ */
5862
+ lookupPostcode({ country, postcode }: {
5863
+ country?: string;
5864
+ postcode: string;
5865
+ }): Promise<{
5866
+ country: string;
5867
+ postcode: string;
5868
+ city: string;
5869
+ state: string;
5870
+ stateCode: string;
5871
+ } | null>;
5782
5872
  deleteAddress(id: string): Promise<{
5783
5873
  id: string;
5784
5874
  deleted: boolean;
@@ -5824,6 +5914,10 @@ declare class WishlistService extends BaseService {
5824
5914
  image_url: string;
5825
5915
  images: string;
5826
5916
  imageList: string[];
5917
+ videos: string[];
5918
+ highlights: string[];
5919
+ freeGift: string | null;
5920
+ soldAtLeast: number | null;
5827
5921
  manageInventory: boolean;
5828
5922
  allowBackorder: boolean;
5829
5923
  stock: number;
@@ -6525,39 +6619,6 @@ declare class AutocompleteService extends MeilisearchService {
6525
6619
  q?: string;
6526
6620
  search?: string;
6527
6621
  }): Promise<{
6528
- data: {
6529
- id: string;
6530
- slug: string;
6531
- title: string;
6532
- name: string;
6533
- description: string;
6534
- currency: string;
6535
- price: number;
6536
- mrp: number;
6537
- minPrice: number;
6538
- maxPrice: number;
6539
- thumbnail: string | null;
6540
- image_url: string | null;
6541
- images: string;
6542
- stock: number;
6543
- hasStock: boolean;
6544
- manageInventory: boolean;
6545
- allowBackorder: boolean;
6546
- productTags: string;
6547
- category: {
6548
- name: string;
6549
- slug: string;
6550
- } | null;
6551
- vendor: {
6552
- businessName: string;
6553
- } | null;
6554
- variants: ReturnType<typeof toVariant>[];
6555
- options: never[];
6556
- ratings: never[];
6557
- link: string;
6558
- updatedAt: string;
6559
- }[];
6560
- } | {
6561
6622
  data: {
6562
6623
  id: string;
6563
6624
  slug: string;
@@ -6582,6 +6643,10 @@ declare class AutocompleteService extends MeilisearchService {
6582
6643
  image_url: string;
6583
6644
  images: string;
6584
6645
  imageList: string[];
6646
+ videos: string[];
6647
+ highlights: string[];
6648
+ freeGift: string | null;
6649
+ soldAtLeast: number | null;
6585
6650
  manageInventory: boolean;
6586
6651
  allowBackorder: boolean;
6587
6652
  stock: number;
@@ -6664,6 +6729,37 @@ declare class AutocompleteService extends MeilisearchService {
6664
6729
  metadata: Record<string, unknown> | null;
6665
6730
  createdAt: string;
6666
6731
  updatedAt: string;
6732
+ }[] | {
6733
+ id: string;
6734
+ slug: string;
6735
+ title: string;
6736
+ name: string;
6737
+ description: string;
6738
+ currency: string;
6739
+ price: number;
6740
+ mrp: number;
6741
+ minPrice: number;
6742
+ maxPrice: number;
6743
+ thumbnail: string | null;
6744
+ image_url: string | null;
6745
+ images: string;
6746
+ stock: number;
6747
+ hasStock: boolean;
6748
+ manageInventory: boolean;
6749
+ allowBackorder: boolean;
6750
+ productTags: string;
6751
+ category: {
6752
+ name: string;
6753
+ slug: string;
6754
+ } | null;
6755
+ vendor: {
6756
+ businessName: string;
6757
+ } | null;
6758
+ variants: ReturnType<typeof toVariant>[];
6759
+ options: never[];
6760
+ ratings: never[];
6761
+ link: string;
6762
+ updatedAt: string;
6667
6763
  }[];
6668
6764
  }>;
6669
6765
  }
@@ -7482,4 +7578,4 @@ declare class B2bService extends BaseService {
7482
7578
  }
7483
7579
  declare const b2bService: B2bService;
7484
7580
 
7485
- export { HomeService as $, type AddOn as A, type B2bPlaced as B, type Cart as C, type CompanyOrder as D, ContactService as E, CountryService as F, CouponService as G, type Credentials as H, type Credit as I, CurrencyService as J, type Customer as K, DealService as L, DemoRequestService as M, type EngineRequest as N, EnquiryService as O, type Envelope as P, type FacetValue as Q, type Faq as R, FaqService as S, FeedbackService as T, type FooterSettings as U, type FreeShipping as V, type Fulfillment as W, GalleryService as X, type HeaderSettings as Y, type HomeLayout as Z, type HomeLayoutSection as _, type Address as a, VariantService as a$, type IdentityAddress as a0, InitService as a1, type Invitation as a2, type LayoutCollection as a3, type LayoutPage as a4, LayoutService as a5, type Lead as a6, type ListMeta as a7, MeilisearchService as a8, type Member as a9, RegionService as aA, type RejectedLine as aB, type Review as aC, type ReviewPage as aD, ReviewService as aE, type SearchDoc as aF, type SearchResult as aG, SearchService as aH, SettingService as aI, type ShippingRate as aJ, type SiteChrome as aK, type SiteFooter as aL, type SiteHeader as aM, type SocialLink as aN, StateService as aO, type StoreProfile as aP, StoreService as aQ, type StorefrontCategory as aR, type StorefrontMenu as aS, type StorefrontOrder as aT, type StorefrontProduct as aU, type ThemeSettings as aV, type ThemeSettingsResult as aW, UploadService as aX, UserService as aY, type Variant as aZ, type VariantImage as a_, type Menu as aa, type MenuItem as ab, MenuService as ac, type MenuSummary as ad, type Money as ae, NewsletterService as af, type Offer as ag, type Order as ah, type OrderLine as ai, OrderService as aj, type PageLayout as ak, PageService as al, type PaymentIntent as am, PaymentMethodService as an, type Plugin as ao, PluginService as ap, PopularSearchService as aq, PopularityService as ar, type Product as as, type ProductFacets as at, type ProductOption as au, ProductService as av, ProfileService as aw, type Quote as ax, REDIRECT_GATEWAYS as ay, ReelsService as az, AddressService as b, stateService as b$, VarniCustomDesignService as b0, VarniCustomProductService as b1, type Vendor as b2, VendorService as b3, WarrantyService as b4, type Wishlist as b5, type WishlistItem as b6, WishlistService as b7, addressService as b8, authService as b9, initService as bA, layoutService as bB, mediaUrl as bC, meilisearchService as bD, menuService as bE, minorToMajor as bF, newsletterService as bG, orderService as bH, ownDomain as bI, pageService as bJ, paymentMethodService as bK, pluginService as bL, pluginsService as bM, popularSearchService as bN, popularityService as bO, priceOf as bP, productImages as bQ, productService as bR, profileService as bS, qs as bT, reelsService as bU, regionService as bV, reviewService as bW, searchService as bX, setRequestHost as bY, settingService as bZ, settingsService as b_, autocompleteService as ba, b2bService as bb, bannerService as bc, blogService as bd, cartService as be, categoryService as bf, chatService as bg, checkoutService as bh, collectionService as bi, contactService as bj, countryService as bk, couponService as bl, currencyExponent as bm, currencyService as bn, dealService as bo, demoRequestService as bp, emptyCart as bq, emptyPage as br, enquiryService as bs, faqService as bt, feedbackService as bu, fromEngineAddress as bv, fromIdentityAddress as bw, fromSearchDoc as bx, galleryService as by, homeService as bz, type AppliedDiscount as c, staticStore as c0, storeForHost as c1, storeService as c2, toAddOn as c3, toCart as c4, toCartLine as c5, toCartOffer as c6, toCategory as c7, toCmsPage as c8, toCollection as c9, toEngineAddress as ca, toFreeShipping as cb, toIdentityAddress as cc, toMajor as cd, toMinor as ce, toOrder as cf, toPage as cg, toProduct as ch, toRating as ci, toStorefrontFacets as cj, toUser as ck, toVariant as cl, toVendor as cm, uploadService as cn, userService as co, variantService as cp, varniCustomDesignService as cq, varniCustomProductService as cr, vendorService as cs, warrantyService as ct, wishlistService as cu, type Approval as d, type AuthResponse as e, AuthService as f, AutocompleteService as g, type B2bRole as h, B2bService as i, BannerService as j, BaseService as k, BlogService as l, type CartLine as m, type CartOffer as n, CartService as o, CatalogService as p, type Category as q, CategoryService as r, ChatService as s, type CheckoutOptions as t, type CheckoutResult as u, CheckoutService as v, type CmsPage as w, type Collection as x, CollectionService as y, type Company as z };
7581
+ export { HomeService as $, type AddOn as A, type B2bPlaced as B, type Cart as C, type CompanyOrder as D, ContactService as E, CountryService as F, CouponService as G, type Credentials as H, type Credit as I, CurrencyService as J, type Customer as K, DealService as L, DemoRequestService as M, type EngineRequest as N, EnquiryService as O, type Envelope as P, type FacetValue as Q, type Faq as R, FaqService as S, FeedbackService as T, type FooterSettings as U, type FreeShipping as V, type Fulfillment as W, GalleryService as X, type HeaderSettings as Y, type HomeLayout as Z, type HomeLayoutSection as _, type Address as a, type VariantImage as a$, type IdentityAddress as a0, InitService as a1, type Invitation as a2, type LayoutCollection as a3, type LayoutPage as a4, LayoutService as a5, type Lead as a6, type ListMeta as a7, MeilisearchService as a8, type Member as a9, ReelsService as aA, RegionService as aB, type RejectedLine as aC, type Review as aD, type ReviewPage as aE, ReviewService as aF, type SearchDoc as aG, type SearchResult as aH, SearchService as aI, SettingService as aJ, type ShippingRate as aK, type SiteChrome as aL, type SiteFooter as aM, type SiteHeader as aN, type SocialLink as aO, StateService as aP, type StoreProfile as aQ, StoreService as aR, type StorefrontCategory as aS, type StorefrontMenu as aT, type StorefrontOrder as aU, type StorefrontProduct as aV, type ThemeSettings as aW, type ThemeSettingsResult as aX, UploadService as aY, UserService as aZ, type Variant as a_, type Menu as aa, type MenuItem as ab, MenuService as ac, type MenuSummary as ad, type Money as ae, NewsletterService as af, type Offer as ag, type Order as ah, type OrderLine as ai, OrderService as aj, type PageLayout as ak, PageService as al, type PaymentIntent as am, PaymentMethodService as an, type Plugin as ao, PluginService as ap, PopularSearchService as aq, PopularityService as ar, type Postcode as as, type Product as at, type ProductFacets as au, type ProductOption as av, ProductService as aw, ProfileService as ax, type Quote as ay, REDIRECT_GATEWAYS as az, AddressService as b, settingService as b$, VariantService as b0, VarniCustomDesignService as b1, VarniCustomProductService as b2, type Vendor as b3, VendorService as b4, WarrantyService as b5, type Wishlist as b6, type WishlistItem as b7, WishlistService as b8, addressService as b9, homeService as bA, initService as bB, layoutService as bC, mediaUrl as bD, meilisearchService as bE, menuService as bF, minorToMajor as bG, newsletterService as bH, orderService as bI, ownDomain as bJ, pageService as bK, paymentMethodService as bL, pluginService as bM, pluginsService as bN, popularSearchService as bO, popularityService as bP, priceOf as bQ, productImages as bR, productService as bS, productVideos as bT, profileService as bU, qs as bV, reelsService as bW, regionService as bX, reviewService as bY, searchService as bZ, setRequestHost as b_, authService as ba, autocompleteService as bb, b2bService as bc, bannerService as bd, blogService as be, cartService as bf, categoryService as bg, chatService as bh, checkoutService as bi, collectionService as bj, contactService as bk, countryService as bl, couponService as bm, currencyExponent as bn, currencyService as bo, dealService as bp, demoRequestService as bq, emptyCart as br, emptyPage as bs, enquiryService as bt, faqService as bu, feedbackService as bv, fromEngineAddress as bw, fromIdentityAddress as bx, fromSearchDoc as by, galleryService as bz, type AppliedDiscount as c, settingsService as c0, stateService as c1, staticStore as c2, storeForHost as c3, storeService as c4, toAddOn as c5, toCart as c6, toCartLine as c7, toCartOffer as c8, toCategory as c9, toCmsPage as ca, toCollection as cb, toEngineAddress as cc, toFreeShipping as cd, toIdentityAddress as ce, toMajor as cf, toMinor as cg, toOrder as ch, toPage as ci, toProduct as cj, toRating as ck, toStorefrontFacets as cl, toUser as cm, toVariant as cn, toVendor as co, uploadService as cp, userService as cq, variantService as cr, varniCustomDesignService as cs, varniCustomProductService as ct, vendorService as cu, warrantyService as cv, wishlistService as cw, type Approval as d, type AuthResponse as e, AuthService as f, AutocompleteService as g, type B2bRole as h, B2bService as i, BannerService as j, BaseService as k, BlogService as l, type CartLine as m, type CartOffer as n, CartService as o, CatalogService as p, type Category as q, CategoryService as r, ChatService as s, type CheckoutOptions as t, type CheckoutResult as u, CheckoutService as v, type CmsPage as w, type Collection as x, CollectionService as y, type Company as z };
package/dist/index.cjs CHANGED
@@ -498,9 +498,27 @@ function productImages(p) {
498
498
  if (url && !out.includes(url)) out.push(url);
499
499
  };
500
500
  push(mediaUrl(p.image_url));
501
+ for (const m of arr(p.media)) if (m.kind === "image") push(mediaUrl(m.url));
501
502
  for (const v of arr(p.variants)) for (const url of variantImages(v)) push(url);
502
503
  return out;
503
504
  }
505
+ function productVideos(p) {
506
+ const out = [];
507
+ for (const m of arr(p.media)) {
508
+ const url = m.kind === "video" ? mediaUrl(m.url) : null;
509
+ if (url && !out.includes(url)) out.push(url);
510
+ }
511
+ return out;
512
+ }
513
+ function highlightsOf(p) {
514
+ const raw = p.metadata?.highlights;
515
+ if (!Array.isArray(raw)) return [];
516
+ return raw.filter((s) => typeof s === "string").map((s) => s.trim()).filter(Boolean);
517
+ }
518
+ function freeGiftOf(p) {
519
+ const raw = p.metadata?.free_gift;
520
+ return typeof raw === "string" && raw.trim() ? raw.trim() : null;
521
+ }
504
522
  function toVariant(v, p, optionless) {
505
523
  const images = variantImages(v);
506
524
  const options = arr(p.options);
@@ -548,6 +566,7 @@ function toProduct(p, extra = {}) {
548
566
  const lead = live[0] ?? arr(p.variants)[0];
549
567
  const optionless = arr(p.options).length === 0;
550
568
  const images = productImages(p);
569
+ const videos = productVideos(p);
551
570
  const prices = live.map((v) => toMajor(v.price));
552
571
  const tracked = live.filter((v) => v.track_inventory);
553
572
  const category = p.category;
@@ -574,8 +593,14 @@ function toProduct(p, extra = {}) {
574
593
  originCountry: lead?.origin_country ?? null,
575
594
  thumbnail: images[0] ?? null,
576
595
  image_url: images[0] ?? null,
577
- images: images.join(","),
596
+ images: [...images, ...videos].join(","),
578
597
  imageList: images,
598
+ videos,
599
+ // What the buy box says beside the price (D134): plain text, drawn as text.
600
+ highlights: highlightsOf(p),
601
+ freeGift: freeGiftOf(p),
602
+ // Counted by the engine, rounded down, and absent rather than zero.
603
+ soldAtLeast: typeof p.sold_at_least === "number" && p.sold_at_least > 0 ? p.sold_at_least : null,
579
604
  // Product-level stock is what a card shows before a variant is picked:
580
605
  // buyable when any live variant is, counted only where counting means
581
606
  // something.
@@ -748,7 +773,9 @@ function toIdentityAddress(a) {
748
773
  state: e.state ?? "",
749
774
  postal_code: e.postal_code,
750
775
  country: e.country,
751
- ...a.label ? { label: String(a.label) } : {},
776
+ // Sent whenever the form has it, empty included: the engine keeps a label it is not sent, so
777
+ // leaving out an emptied one would keep the old Home or Work (D134).
778
+ ...typeof a.label === "string" ? { label: a.label } : {},
752
779
  ...a.isPrimary ? { is_default: true } : {}
753
780
  };
754
781
  }
@@ -1189,14 +1216,17 @@ var CatalogService = class extends BaseService {
1189
1216
  const attr = Object.entries(q.attributes ?? {}).flatMap(
1190
1217
  ([handle, values]) => values.filter(Boolean).map((v) => `${handle}:${v}`)
1191
1218
  );
1192
- if (q.facets && !legacyListing.has(this.engineBase())) {
1219
+ const refined = attr.length > 0 || !!(q.tags?.length || q.vendors?.length || q.productTypes?.length);
1220
+ const triedIndex = !!search && !refined;
1221
+ const counted = q.facets && !legacyListing.has(this.engineBase());
1222
+ const facetListing = async (page2, limit2) => {
1193
1223
  const { currency } = await this.facts.ready();
1194
1224
  const minor = (n) => Number.isFinite(n) ? Math.max(0, toMinor(n, currency)) : void 0;
1195
- const env2 = await this.engine("/api/products", {
1225
+ return this.engine("/api/products", {
1196
1226
  query: {
1197
1227
  q: search,
1198
- page,
1199
- limit,
1228
+ page: page2,
1229
+ limit: limit2,
1200
1230
  channel: this.creds.channel,
1201
1231
  category: q.category,
1202
1232
  tag: q.tags,
@@ -1209,6 +1239,16 @@ var CatalogService = class extends BaseService {
1209
1239
  facets: 1
1210
1240
  }
1211
1241
  });
1242
+ };
1243
+ if (triedIndex && await this.facts.pluginOn("meilisearch")) {
1244
+ const [found, rail] = await Promise.all([
1245
+ this.fromIndex(q, { page, limit, search, sortKey, wantsRange, hierarchy }),
1246
+ counted ? facetListing(1, 1).catch(() => null) : null
1247
+ ]);
1248
+ if (found) return rail?.meta?.facets ? { ...found, facets: rail.meta.facets } : found;
1249
+ }
1250
+ if (counted) {
1251
+ const env2 = await facetListing(page, limit);
1212
1252
  if (env2.meta?.facets) {
1213
1253
  return {
1214
1254
  ...toPage(env2, (p) => toProduct(p)),
@@ -1219,39 +1259,9 @@ var CatalogService = class extends BaseService {
1219
1259
  }
1220
1260
  legacyListing.add(this.engineBase());
1221
1261
  }
1222
- if ((sortKey || wantsRange) && await this.facts.pluginOn("meilisearch")) {
1223
- const filters = [];
1224
- if (q.category) {
1225
- const names = (await this.facts.subtree(q.category).catch(() => [])).map(
1226
- (c) => quote(c.full_name)
1227
- );
1228
- if (!names.length) return { ...emptyCatalog(limit), categoryHierarchy: hierarchy, sorted: true };
1229
- filters.push(`category IN [${names.join(", ")}]`);
1230
- }
1231
- if (wantsRange) {
1232
- const { currency } = await this.facts.ready();
1233
- if (Number.isFinite(q.priceFrom)) filters.push(`price_minor >= ${toMinor(q.priceFrom, currency)}`);
1234
- if (Number.isFinite(q.priceTo)) filters.push(`price_minor <= ${toMinor(q.priceTo, currency)}`);
1235
- }
1236
- const res = await this.data("/x/meilisearch/search", {
1237
- query: {
1238
- q: search ?? "",
1239
- limit,
1240
- offset: (page - 1) * limit,
1241
- filter: filters.join(" AND ") || void 0,
1242
- sort: sortKey
1243
- }
1244
- });
1245
- const total = res.total ?? 0;
1246
- return {
1247
- data: (res.hits ?? []).map(fromSearchDoc),
1248
- count: total,
1249
- pageSize: limit,
1250
- noOfPage: Math.max(1, Math.ceil(total / limit)),
1251
- page,
1252
- categoryHierarchy: hierarchy,
1253
- sorted: true
1254
- };
1262
+ if (!triedIndex && (sortKey || wantsRange)) {
1263
+ const found = await this.fromIndex(q, { page, limit, search, sortKey, wantsRange, hierarchy });
1264
+ if (found) return found;
1255
1265
  }
1256
1266
  const sorted = !sortKey && !wantsRange;
1257
1267
  if (q.category && !search) {
@@ -1271,6 +1281,45 @@ var CatalogService = class extends BaseService {
1271
1281
  });
1272
1282
  return { ...toPage(env, (p) => toProduct(p)), categoryHierarchy: hierarchy, sorted };
1273
1283
  }
1284
+ /**
1285
+ * The shelf from the Meilisearch module, or null when the store has it off,
1286
+ * sells through a channel, finds nothing for the words, or it cannot answer (Meilisearch down: the engine says `unavailable`), so
1287
+ * the caller asks the database instead of showing the shopper an error.
1288
+ */
1289
+ async fromIndex(q, o) {
1290
+ if (this.creds.channel || !await this.facts.pluginOn("meilisearch")) return null;
1291
+ const filters = [];
1292
+ if (q.category) {
1293
+ const names = (await this.facts.subtree(q.category).catch(() => [])).map((c) => quote(c.full_name));
1294
+ if (!names.length) return { ...emptyCatalog(o.limit), categoryHierarchy: o.hierarchy, sorted: true };
1295
+ filters.push(`category IN [${names.join(", ")}]`);
1296
+ }
1297
+ if (o.wantsRange) {
1298
+ const { currency } = await this.facts.ready();
1299
+ if (Number.isFinite(q.priceFrom)) filters.push(`price_minor >= ${toMinor(q.priceFrom, currency)}`);
1300
+ if (Number.isFinite(q.priceTo)) filters.push(`price_minor <= ${toMinor(q.priceTo, currency)}`);
1301
+ }
1302
+ const res = await this.data("/x/meilisearch/search", {
1303
+ query: {
1304
+ q: o.search ?? "",
1305
+ limit: o.limit,
1306
+ offset: (o.page - 1) * o.limit,
1307
+ filter: filters.join(" AND ") || void 0,
1308
+ sort: o.sortKey
1309
+ }
1310
+ }).catch(() => null);
1311
+ if (!res || res.unavailable || o.search && !res.hits?.length) return null;
1312
+ const total = res.total ?? 0;
1313
+ return {
1314
+ data: (res.hits ?? []).map(fromSearchDoc),
1315
+ count: total,
1316
+ pageSize: o.limit,
1317
+ noOfPage: Math.max(1, Math.ceil(total / o.limit)),
1318
+ page: o.page,
1319
+ categoryHierarchy: o.hierarchy,
1320
+ sorted: true
1321
+ };
1322
+ }
1274
1323
  };
1275
1324
  function emptyCatalog(limit = PAGE_SIZE) {
1276
1325
  return { data: [], count: 0, pageSize: limit, noOfPage: 0, page: 1 };
@@ -1568,10 +1617,8 @@ var MeilisearchService = class extends CatalogService {
1568
1617
  async searchAutoComplete({ query, search, limit = 8 } = {}) {
1569
1618
  const q = (query ?? search ?? "").trim();
1570
1619
  if (!q) return { data: [] };
1571
- if (await this.facts.pluginOn("meilisearch")) {
1572
- const res = await this.data("/x/meilisearch/search", { query: { q, limit } });
1573
- return { data: (res.hits ?? []).map(fromSearchDoc) };
1574
- }
1620
+ const found = await this.fromIndex({}, { page: 1, limit, search: q, wantsRange: false, hierarchy: [] });
1621
+ if (found) return { data: found.data };
1575
1622
  const rows = await this.data("/api/products", { query: { q, limit, channel: this.creds.channel } }) ?? [];
1576
1623
  return { data: rows.map((p) => toProduct(p)) };
1577
1624
  }
@@ -2688,6 +2735,24 @@ var AddressService = class extends BaseService {
2688
2735
  });
2689
2736
  return fromIdentityAddress(a, currentMe()?.email);
2690
2737
  }
2738
+ /**
2739
+ * The city and state for a postcode (D134), for the address form to fill
2740
+ * in. India's six-digit PIN codes only, from the directory the engine was
2741
+ * given; null for anything it cannot answer, so the form simply leaves the
2742
+ * fields to the shopper.
2743
+ */
2744
+ async lookupPostcode({ country = "IN", postcode }) {
2745
+ const code = String(postcode ?? "").trim();
2746
+ const cc = String(country ?? "").trim().toUpperCase();
2747
+ if (cc !== "IN" || !/^[1-9][0-9]{5}$/.test(code)) return null;
2748
+ try {
2749
+ const p = await this.data(`/api/postcodes/${cc}/${code}`);
2750
+ return { country: p.country, postcode: p.postcode, city: p.city, state: p.state, stateCode: p.state_code };
2751
+ } catch (err) {
2752
+ if (err instanceof GoCommerceError && (err.status === 404 || err.status === 400)) return null;
2753
+ throw err;
2754
+ }
2755
+ }
2691
2756
  async deleteAddress(id2) {
2692
2757
  await this.engine(`/x/identity/me/addresses/${enc(id2)}`, { method: "DELETE", auth: true });
2693
2758
  return { id: String(id2), deleted: true };
@@ -3812,6 +3877,7 @@ exports.popularityService = popularityService;
3812
3877
  exports.priceOf = priceOf;
3813
3878
  exports.productImages = productImages;
3814
3879
  exports.productService = productService;
3880
+ exports.productVideos = productVideos;
3815
3881
  exports.profileService = profileService;
3816
3882
  exports.qs = qs;
3817
3883
  exports.readStaticStore = readStaticStore;