@misiki/gocommerce-connector 0.11.0 → 0.13.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.
@@ -1 +1 @@
1
- export { a as AddressService, c as Approval, e as AuthService, f as AutocompleteService, B as B2bPlaced, g as B2bRole, h as B2bService, i as BannerService, j as BaseService, k as BlogService, m as CartService, n as CatalogService, p as CategoryService, q as ChatService, t as CheckoutService, w as CollectionService, x as Company, y as CompanyOrder, z as ContactService, D as CountryService, E as CouponService, G as Credit, H as CurrencyService, J as DealService, K as DemoRequestService, L as EngineRequest, M as EnquiryService, Q as FaqService, R as FeedbackService, S as FooterSettings, U as GalleryService, V as HeaderSettings, W as HomeLayout, X as HomeLayoutSection, Y as HomeService, _ as InitService, $ as Invitation, a0 as LayoutCollection, a1 as LayoutPage, a2 as LayoutService, a3 as Lead, a5 as MeilisearchService, a6 as Member, a9 as MenuService, ac as NewsletterService, ag as OrderService, ah as PageLayout, ai as PageService, ak as PaymentMethodService, am as PluginService, am as PluginsService, an as PopularSearchService, ao as PopularityService, as as ProductService, at as ProfileService, au as Quote, av as REDIRECT_GATEWAYS, aw as ReelsService, ax as RegionService, ay as RejectedLine, aB as ReviewService, aE as SearchService, aF as SettingService, aF as SettingsService, aH as SiteChrome, aI as SiteFooter, aJ as SiteHeader, aK as SocialLink, aL as StateService, aN as StoreService, aP as StorefrontMenu, aS as ThemeSettings, aT as ThemeSettingsResult, aU as UploadService, aV as UserService, aY as VariantService, aZ as VarniCustomDesignService, a_ as VarniCustomProductService, b0 as VendorService, b1 as WarrantyService, b4 as WishlistService, b5 as addressService, b6 as authService, b7 as autocompleteService, b8 as b2bService, b9 as bannerService, ba as blogService, bb as cartService, bc as categoryService, bd as chatService, be as checkoutService, bf as collectionService, bg as contactService, bh as countryService, bi as couponService, bk as currencyService, bl as dealService, bm as demoRequestService, bo as emptyPage, bp as enquiryService, bq as faqService, br as feedbackService, bv as galleryService, bw as homeService, bx as initService, by as layoutService, bz as mediaUrl, bA as meilisearchService, bB as menuService, bD as newsletterService, bE as orderService, bF as ownDomain, bG as pageService, bH as paymentMethodService, bI as pluginService, bJ as pluginsService, bK as popularSearchService, bL as popularityService, bO as productService, bP as profileService, bQ as qs, bR as reelsService, bS as regionService, bT as reviewService, bU as searchService, bV as setRequestHost, bW as settingService, bX as settingsService, bY as stateService, bZ as staticStore, b_ as storeForHost, b$ as storeService, ca as toPage, cd as toStorefrontFacets, ch as uploadService, ci as userService, cj as variantService, ck as varniCustomDesignService, cl as varniCustomProductService, cm as vendorService, cn as warrantyService, co as wishlistService } from '../index-90wdO5MM.cjs';
1
+ export { b as AddressService, d as Approval, f as AuthService, g as AutocompleteService, B as B2bPlaced, h as B2bRole, i as B2bService, j as BannerService, k as BaseService, l as BlogService, o as CartService, p as CatalogService, r as CategoryService, s as ChatService, v as CheckoutService, y as CollectionService, z as Company, D as CompanyOrder, E as ContactService, F as CountryService, G as CouponService, I as Credit, J as CurrencyService, L as DealService, M as DemoRequestService, N as EngineRequest, O as EnquiryService, S as FaqService, T as FeedbackService, U as FooterSettings, X as GalleryService, Y as HeaderSettings, Z as HomeLayout, _ as HomeLayoutSection, $ as HomeService, a1 as InitService, a2 as Invitation, a3 as LayoutCollection, a4 as LayoutPage, a5 as LayoutService, a6 as Lead, a8 as MeilisearchService, a9 as Member, ac as MenuService, af as NewsletterService, aj as OrderService, ak as PageLayout, al as PageService, an as PaymentMethodService, ap as PluginService, ap as PluginsService, aq as PopularSearchService, ar as PopularityService, aw as ProductService, ax as ProfileService, ay as Quote, az as REDIRECT_GATEWAYS, aA as ReelsService, aB as RegionService, aC as RejectedLine, aF as ReviewService, aI as SearchService, aJ as SettingService, aJ as SettingsService, aL as SiteChrome, aM as SiteFooter, aN as SiteHeader, aO as SocialLink, aP as StateService, aR as StoreService, aT as StorefrontMenu, aW as ThemeSettings, aX as ThemeSettingsResult, aY as UploadService, aZ as UserService, b0 as VariantService, b1 as VarniCustomDesignService, b2 as VarniCustomProductService, b4 as VendorService, b5 as WarrantyService, b8 as WishlistService, b9 as addressService, ba as authService, bb as autocompleteService, bc as b2bService, bd as bannerService, be as blogService, bf as cartService, bg as categoryService, bh as chatService, bi as checkoutService, bj as collectionService, bk as contactService, bl as countryService, bm as couponService, bo as currencyService, bp as dealService, bq as demoRequestService, bs as emptyPage, bt as enquiryService, bu as faqService, bv as feedbackService, bz as galleryService, bA as homeService, bB as initService, bC as layoutService, bD as mediaUrl, bE as meilisearchService, bF as menuService, bH as newsletterService, bI as orderService, bJ as ownDomain, bK as pageService, bL as paymentMethodService, bM as pluginService, bN as pluginsService, bO as popularSearchService, bP as popularityService, bS as productService, bU as profileService, bV as qs, bW as reelsService, bX as regionService, bY as reviewService, bZ as searchService, b_ as setRequestHost, b$ as settingService, c0 as settingsService, c1 as stateService, c2 as staticStore, c3 as storeForHost, c4 as storeService, ci as toPage, cl as toStorefrontFacets, cp as uploadService, cq as userService, cr as variantService, cs as varniCustomDesignService, ct as varniCustomProductService, cu as vendorService, cv as warrantyService, cw as wishlistService } from '../index-DHKyh3CU.cjs';
@@ -1 +1 @@
1
- export { a as AddressService, c as Approval, e as AuthService, f as AutocompleteService, B as B2bPlaced, g as B2bRole, h as B2bService, i as BannerService, j as BaseService, k as BlogService, m as CartService, n as CatalogService, p as CategoryService, q as ChatService, t as CheckoutService, w as CollectionService, x as Company, y as CompanyOrder, z as ContactService, D as CountryService, E as CouponService, G as Credit, H as CurrencyService, J as DealService, K as DemoRequestService, L as EngineRequest, M as EnquiryService, Q as FaqService, R as FeedbackService, S as FooterSettings, U as GalleryService, V as HeaderSettings, W as HomeLayout, X as HomeLayoutSection, Y as HomeService, _ as InitService, $ as Invitation, a0 as LayoutCollection, a1 as LayoutPage, a2 as LayoutService, a3 as Lead, a5 as MeilisearchService, a6 as Member, a9 as MenuService, ac as NewsletterService, ag as OrderService, ah as PageLayout, ai as PageService, ak as PaymentMethodService, am as PluginService, am as PluginsService, an as PopularSearchService, ao as PopularityService, as as ProductService, at as ProfileService, au as Quote, av as REDIRECT_GATEWAYS, aw as ReelsService, ax as RegionService, ay as RejectedLine, aB as ReviewService, aE as SearchService, aF as SettingService, aF as SettingsService, aH as SiteChrome, aI as SiteFooter, aJ as SiteHeader, aK as SocialLink, aL as StateService, aN as StoreService, aP as StorefrontMenu, aS as ThemeSettings, aT as ThemeSettingsResult, aU as UploadService, aV as UserService, aY as VariantService, aZ as VarniCustomDesignService, a_ as VarniCustomProductService, b0 as VendorService, b1 as WarrantyService, b4 as WishlistService, b5 as addressService, b6 as authService, b7 as autocompleteService, b8 as b2bService, b9 as bannerService, ba as blogService, bb as cartService, bc as categoryService, bd as chatService, be as checkoutService, bf as collectionService, bg as contactService, bh as countryService, bi as couponService, bk as currencyService, bl as dealService, bm as demoRequestService, bo as emptyPage, bp as enquiryService, bq as faqService, br as feedbackService, bv as galleryService, bw as homeService, bx as initService, by as layoutService, bz as mediaUrl, bA as meilisearchService, bB as menuService, bD as newsletterService, bE as orderService, bF as ownDomain, bG as pageService, bH as paymentMethodService, bI as pluginService, bJ as pluginsService, bK as popularSearchService, bL as popularityService, bO as productService, bP as profileService, bQ as qs, bR as reelsService, bS as regionService, bT as reviewService, bU as searchService, bV as setRequestHost, bW as settingService, bX as settingsService, bY as stateService, bZ as staticStore, b_ as storeForHost, b$ as storeService, ca as toPage, cd as toStorefrontFacets, ch as uploadService, ci as userService, cj as variantService, ck as varniCustomDesignService, cl as varniCustomProductService, cm as vendorService, cn as warrantyService, co as wishlistService } from '../index-90wdO5MM.js';
1
+ export { b as AddressService, d as Approval, f as AuthService, g as AutocompleteService, B as B2bPlaced, h as B2bRole, i as B2bService, j as BannerService, k as BaseService, l as BlogService, o as CartService, p as CatalogService, r as CategoryService, s as ChatService, v as CheckoutService, y as CollectionService, z as Company, D as CompanyOrder, E as ContactService, F as CountryService, G as CouponService, I as Credit, J as CurrencyService, L as DealService, M as DemoRequestService, N as EngineRequest, O as EnquiryService, S as FaqService, T as FeedbackService, U as FooterSettings, X as GalleryService, Y as HeaderSettings, Z as HomeLayout, _ as HomeLayoutSection, $ as HomeService, a1 as InitService, a2 as Invitation, a3 as LayoutCollection, a4 as LayoutPage, a5 as LayoutService, a6 as Lead, a8 as MeilisearchService, a9 as Member, ac as MenuService, af as NewsletterService, aj as OrderService, ak as PageLayout, al as PageService, an as PaymentMethodService, ap as PluginService, ap as PluginsService, aq as PopularSearchService, ar as PopularityService, aw as ProductService, ax as ProfileService, ay as Quote, az as REDIRECT_GATEWAYS, aA as ReelsService, aB as RegionService, aC as RejectedLine, aF as ReviewService, aI as SearchService, aJ as SettingService, aJ as SettingsService, aL as SiteChrome, aM as SiteFooter, aN as SiteHeader, aO as SocialLink, aP as StateService, aR as StoreService, aT as StorefrontMenu, aW as ThemeSettings, aX as ThemeSettingsResult, aY as UploadService, aZ as UserService, b0 as VariantService, b1 as VarniCustomDesignService, b2 as VarniCustomProductService, b4 as VendorService, b5 as WarrantyService, b8 as WishlistService, b9 as addressService, ba as authService, bb as autocompleteService, bc as b2bService, bd as bannerService, be as blogService, bf as cartService, bg as categoryService, bh as chatService, bi as checkoutService, bj as collectionService, bk as contactService, bl as countryService, bm as couponService, bo as currencyService, bp as dealService, bq as demoRequestService, bs as emptyPage, bt as enquiryService, bu as faqService, bv as feedbackService, bz as galleryService, bA as homeService, bB as initService, bC as layoutService, bD as mediaUrl, bE as meilisearchService, bF as menuService, bH as newsletterService, bI as orderService, bJ as ownDomain, bK as pageService, bL as paymentMethodService, bM as pluginService, bN as pluginsService, bO as popularSearchService, bP as popularityService, bS as productService, bU as profileService, bV as qs, bW as reelsService, bX as regionService, bY as reviewService, bZ as searchService, b_ as setRequestHost, b$ as settingService, c0 as settingsService, c1 as stateService, c2 as staticStore, c3 as storeForHost, c4 as storeService, ci as toPage, cl as toStorefrontFacets, cp as uploadService, cq as userService, cr as variantService, cs as varniCustomDesignService, ct as varniCustomProductService, cu as vendorService, cv as warrantyService, cw as wishlistService } from '../index-DHKyh3CU.js';
@@ -464,9 +464,27 @@ function productImages(p) {
464
464
  if (url && !out.includes(url)) out.push(url);
465
465
  };
466
466
  push(mediaUrl(p.image_url));
467
+ for (const m of arr(p.media)) if (m.kind === "image") push(mediaUrl(m.url));
467
468
  for (const v of arr(p.variants)) for (const url of variantImages(v)) push(url);
468
469
  return out;
469
470
  }
471
+ function productVideos(p) {
472
+ const out = [];
473
+ for (const m of arr(p.media)) {
474
+ const url = m.kind === "video" ? mediaUrl(m.url) : null;
475
+ if (url && !out.includes(url)) out.push(url);
476
+ }
477
+ return out;
478
+ }
479
+ function highlightsOf(p) {
480
+ const raw = p.metadata?.highlights;
481
+ if (!Array.isArray(raw)) return [];
482
+ return raw.filter((s) => typeof s === "string").map((s) => s.trim()).filter(Boolean);
483
+ }
484
+ function freeGiftOf(p) {
485
+ const raw = p.metadata?.free_gift;
486
+ return typeof raw === "string" && raw.trim() ? raw.trim() : null;
487
+ }
470
488
  function toVariant(v, p, optionless) {
471
489
  const images = variantImages(v);
472
490
  const options = arr(p.options);
@@ -514,6 +532,7 @@ function toProduct(p, extra = {}) {
514
532
  const lead = live[0] ?? arr(p.variants)[0];
515
533
  const optionless = arr(p.options).length === 0;
516
534
  const images = productImages(p);
535
+ const videos = productVideos(p);
517
536
  const prices = live.map((v) => toMajor(v.price));
518
537
  const tracked = live.filter((v) => v.track_inventory);
519
538
  const category = p.category;
@@ -540,8 +559,14 @@ function toProduct(p, extra = {}) {
540
559
  originCountry: lead?.origin_country ?? null,
541
560
  thumbnail: images[0] ?? null,
542
561
  image_url: images[0] ?? null,
543
- images: images.join(","),
562
+ images: [...images, ...videos].join(","),
544
563
  imageList: images,
564
+ videos,
565
+ // What the buy box says beside the price (D134): plain text, drawn as text.
566
+ highlights: highlightsOf(p),
567
+ freeGift: freeGiftOf(p),
568
+ // Counted by the engine, rounded down, and absent rather than zero.
569
+ soldAtLeast: typeof p.sold_at_least === "number" && p.sold_at_least > 0 ? p.sold_at_least : null,
545
570
  // Product-level stock is what a card shows before a variant is picked:
546
571
  // buyable when any live variant is, counted only where counting means
547
572
  // something.
@@ -714,7 +739,9 @@ function toIdentityAddress(a) {
714
739
  state: e.state ?? "",
715
740
  postal_code: e.postal_code,
716
741
  country: e.country,
717
- ...a.label ? { label: String(a.label) } : {},
742
+ // Sent whenever the form has it, empty included: the engine keeps a label it is not sent, so
743
+ // leaving out an emptied one would keep the old Home or Work (D134).
744
+ ...typeof a.label === "string" ? { label: a.label } : {},
718
745
  ...a.isPrimary ? { is_default: true } : {}
719
746
  };
720
747
  }
@@ -731,7 +758,12 @@ function toCartLine(l, extra = {}) {
731
758
  variantTitle: l.variant_label ?? "",
732
759
  qty: l.quantity,
733
760
  price: toMajor(l.unit_price),
734
- mrp: toMajor(l.unit_price),
761
+ // The variant's compare-at price, where the shop set one above what the
762
+ // line costs: what the basket's "you save" is measured from.
763
+ mrp: l.compare_at_price && l.compare_at_price.amount_minor > l.unit_price.amount_minor ? toMajor(l.compare_at_price) : toMajor(l.unit_price),
764
+ /** The add-on this line was bought as (D133), or null on an ordinary line. */
765
+ addOnId: l.add_on_id ? str(l.add_on_id) : null,
766
+ addOnFor: l.add_on_for ? str(l.add_on_for) : null,
735
767
  subtotal: toMajor(l.total),
736
768
  total: toMajor(l.total),
737
769
  inStock: l.in_stock,
@@ -964,6 +996,45 @@ function toUser(c) {
964
996
  updatedAt: c.updated_at
965
997
  };
966
998
  }
999
+ function toAddOn(a) {
1000
+ return {
1001
+ id: str(a.id),
1002
+ productId: str(a.item.product_id),
1003
+ variantId: str(a.variant_id),
1004
+ slug: a.item.slug,
1005
+ title: a.item.title,
1006
+ variantTitle: a.item.variant_label ?? "",
1007
+ thumbnail: mediaUrl(a.item.image_url ?? null),
1008
+ price: toMajor(a.offer_price ?? a.price),
1009
+ regularPrice: toMajor(a.price),
1010
+ hasOffer: !!a.offer_price && a.offer_price.amount_minor < a.price.amount_minor,
1011
+ inStock: a.item.in_stock
1012
+ };
1013
+ }
1014
+ function toCartOffer(o, currency) {
1015
+ const isPercent = o.kind === "percentage";
1016
+ return {
1017
+ code: o.code,
1018
+ title: o.title,
1019
+ isPercent,
1020
+ freeShipping: o.kind === "free_shipping",
1021
+ /** The percentage for a percentage code, the amount for a fixed one. */
1022
+ value: isPercent ? (o.value_bp ?? 0) / 100 : minorToMajor(o.value_minor ?? 0, currency),
1023
+ minAmount: o.min_subtotal_minor ? minorToMajor(o.min_subtotal_minor, currency) : null,
1024
+ applies: o.applies,
1025
+ amount: o.amount ? toMajor(o.amount) : null,
1026
+ remaining: o.remaining ? toMajor(o.remaining) : null,
1027
+ reason: o.reason ?? ""
1028
+ };
1029
+ }
1030
+ function toFreeShipping(f) {
1031
+ return {
1032
+ qualifies: f.qualifies,
1033
+ threshold: f.threshold ? toMajor(f.threshold) : null,
1034
+ remaining: f.remaining ? toMajor(f.remaining) : null,
1035
+ subtotal: toMajor(f.subtotal)
1036
+ };
1037
+ }
967
1038
 
968
1039
  // src/cache.ts
969
1040
  var TTL_MS = 6e4;
@@ -1288,6 +1359,36 @@ var ProductService = class extends CatalogService {
1288
1359
  if (!category) return this.list({ page, limit });
1289
1360
  return this.list({ page, limit, categories: category.slug });
1290
1361
  }
1362
+ /**
1363
+ * What the shop offers with a product, ticked in its buy box (D133): each
1364
+ * add-on at the price ticking it adds. Only add-ons that can be bought
1365
+ * arrive; an engine without the route offers none.
1366
+ */
1367
+ async listAddOns({ product }) {
1368
+ const p = await this.findProduct(String(product));
1369
+ try {
1370
+ return (await this.data("/api/add-ons", { query: { product_id: p.id } }) ?? []).map(toAddOn);
1371
+ } catch (err) {
1372
+ if (err instanceof GoCommerceError && err.status === 404) return [];
1373
+ throw err;
1374
+ }
1375
+ }
1376
+ /**
1377
+ * "You may also like": the products the shop chose for this one, at their
1378
+ * own prices (D133). Curated only, and empty when none were chosen: the
1379
+ * related products already fill in from the category, and the page should
1380
+ * not draw the same fill twice.
1381
+ */
1382
+ async listCrossSells({ product, limit }) {
1383
+ const p = await this.findProduct(String(product));
1384
+ try {
1385
+ const rows = await this.data("/api/cross-sells", { query: { product_id: p.id, limit } }) ?? [];
1386
+ return rows.map((r) => toProduct(r));
1387
+ } catch (err) {
1388
+ if (err instanceof GoCommerceError && err.status === 404) return [];
1389
+ throw err;
1390
+ }
1391
+ }
1291
1392
  async relatedTo(slug, limit) {
1292
1393
  const size = Math.min(100, Math.max(1, Number(limit) || PAGE_SIZE));
1293
1394
  const p = await this.findProduct(slug);
@@ -1627,6 +1728,88 @@ var CartService = class extends BaseService {
1627
1728
  throw err;
1628
1729
  }
1629
1730
  }
1731
+ /**
1732
+ * Adds an add-on from a product's "Complete the set" (D133) at its offer
1733
+ * price. The product it is offered with has to be in the bag already, so
1734
+ * this is called after adding it; the engine refuses one too many with the
1735
+ * sentence the shopper is shown.
1736
+ */
1737
+ async addAddOn({ cartId, addOnId, qty = 1 }) {
1738
+ const id2 = clean(cartId) ?? storedCartId();
1739
+ if (!id2) throw new GoCommerceError("Add the product to your bag first.", 409);
1740
+ return this.present(
1741
+ await this.data(`/api/carts/${encodeURIComponent(id2)}/line-items`, {
1742
+ method: "POST",
1743
+ body: { add_on_id: Number(addOnId), quantity: Number(qty) }
1744
+ })
1745
+ );
1746
+ }
1747
+ /**
1748
+ * The codes the shop chose to show (D133), each with what it takes off this
1749
+ * bag or how much more the bag needs. None without a bag.
1750
+ */
1751
+ async getOffers({ cartId } = {}) {
1752
+ const id2 = clean(cartId) ?? storedCartId();
1753
+ if (!id2) return [];
1754
+ try {
1755
+ const rows = await this.data(`/api/carts/${encodeURIComponent(id2)}/offers`) ?? [];
1756
+ const currency = await this.currency();
1757
+ return rows.map((o) => toCartOffer(o, o.amount?.currency ?? o.remaining?.currency ?? currency));
1758
+ } catch (err) {
1759
+ if (err instanceof GoCommerceError && err.status === 404) return [];
1760
+ throw err;
1761
+ }
1762
+ }
1763
+ /**
1764
+ * How far the bag is from free delivery (D133), read from the store's own
1765
+ * rates for the country (the store's own when none is given). Null when
1766
+ * the engine cannot say: a bar with a made-up figure is worse than none.
1767
+ */
1768
+ async getFreeShipping({ cartId, country, state } = {}) {
1769
+ const id2 = clean(cartId) ?? storedCartId();
1770
+ if (!id2) return null;
1771
+ const where = country ?? cartExtras(id2).shippingAddress?.country ?? void 0;
1772
+ try {
1773
+ return toFreeShipping(
1774
+ await this.data(`/api/carts/${encodeURIComponent(id2)}/free-shipping`, {
1775
+ query: { country: where || void 0, state: state || void 0 }
1776
+ })
1777
+ );
1778
+ } catch (err) {
1779
+ if (err instanceof GoCommerceError && err.status === 404) return null;
1780
+ throw err;
1781
+ }
1782
+ }
1783
+ /**
1784
+ * "You may be interested in" (D133): what the bag's products suggest, less
1785
+ * what it holds; with nothing curated, the first product's related
1786
+ * products, still less what it holds.
1787
+ */
1788
+ async listCrossSells({ cartId, limit = 12 } = {}) {
1789
+ const id2 = clean(cartId) ?? storedCartId();
1790
+ if (!id2) return [];
1791
+ let curated = [];
1792
+ try {
1793
+ curated = await this.data(`/api/carts/${encodeURIComponent(id2)}/cross-sells`, { query: { limit } }) ?? [];
1794
+ } catch (err) {
1795
+ if (!(err instanceof GoCommerceError) || err.status !== 404) throw err;
1796
+ }
1797
+ if (curated.length) return curated.map((p) => toProduct(p));
1798
+ let cart;
1799
+ try {
1800
+ cart = await this.data(`/api/carts/${encodeURIComponent(id2)}`);
1801
+ } catch {
1802
+ return [];
1803
+ }
1804
+ const held = new Set((cart.line_items ?? []).map((l) => String(l.product_id)));
1805
+ const first = cart.line_items?.[0];
1806
+ if (!first) return [];
1807
+ const related = await new ProductService(this._fetch).listRelatedProducts({
1808
+ product: String(first.product_id),
1809
+ limit: limit + held.size
1810
+ });
1811
+ return related.data.filter((p) => !held.has(String(p.id))).slice(0, limit);
1812
+ }
1630
1813
  /** `qty` is the new total; 0 takes the line out. */
1631
1814
  async updateCart({
1632
1815
  cartId,
@@ -2060,7 +2243,20 @@ var paymentMethodService = new PaymentMethodService();
2060
2243
  // src/services/coupon-service.ts
2061
2244
  var CouponService = class extends BaseService {
2062
2245
  async listCoupons(_args = {}) {
2063
- return emptyPage();
2246
+ const offers = await new CartService(this._fetch).getOffers().catch(() => []);
2247
+ if (!offers.length) return emptyPage();
2248
+ const data = offers.map((o) => ({
2249
+ id: o.code,
2250
+ code: o.code,
2251
+ title: o.title,
2252
+ isPercent: o.isPercent,
2253
+ amount: o.value,
2254
+ minAmount: o.minAmount,
2255
+ description: o.applies ? o.title : o.remaining !== null ? `${o.title}. Add ${o.remaining} more to use this.` : o.reason || o.title,
2256
+ applies: o.applies,
2257
+ remaining: o.remaining
2258
+ }));
2259
+ return { data, count: data.length, pageSize: data.length, noOfPage: 1, page: 1 };
2064
2260
  }
2065
2261
  };
2066
2262
  var couponService = new CouponService();
@@ -2498,6 +2694,24 @@ var AddressService = class extends BaseService {
2498
2694
  });
2499
2695
  return fromIdentityAddress(a, currentMe()?.email);
2500
2696
  }
2697
+ /**
2698
+ * The city and state for a postcode (D134), for the address form to fill
2699
+ * in. India's six-digit PIN codes only, from the directory the engine was
2700
+ * given; null for anything it cannot answer, so the form simply leaves the
2701
+ * fields to the shopper.
2702
+ */
2703
+ async lookupPostcode({ country = "IN", postcode }) {
2704
+ const code = String(postcode ?? "").trim();
2705
+ const cc = String(country ?? "").trim().toUpperCase();
2706
+ if (cc !== "IN" || !/^[1-9][0-9]{5}$/.test(code)) return null;
2707
+ try {
2708
+ const p = await this.data(`/api/postcodes/${cc}/${code}`);
2709
+ return { country: p.country, postcode: p.postcode, city: p.city, state: p.state, stateCode: p.state_code };
2710
+ } catch (err) {
2711
+ if (err instanceof GoCommerceError && (err.status === 404 || err.status === 400)) return null;
2712
+ throw err;
2713
+ }
2714
+ }
2501
2715
  async deleteAddress(id2) {
2502
2716
  await this.engine(`/x/identity/me/addresses/${enc(id2)}`, { method: "DELETE", auth: true });
2503
2717
  return { id: String(id2), deleted: true };
@@ -2810,7 +3024,10 @@ var StoreService = class extends BaseService {
2810
3024
  },
2811
3025
  // The footer's sign-up box posts to ext/newsletter, and the theme editor's footer
2812
3026
  // switch (D131) can only show it while that is on.
2813
- newsletter: { ...basePlugins.newsletter, ...flag(plugins.has("newsletter")) }
3027
+ newsletter: { ...basePlugins.newsletter, ...flag(plugins.has("newsletter")) },
3028
+ // Discount codes are core: every GoCommerce store takes them, so
3029
+ // the code box is shown whatever the static record says.
3030
+ isDiscountCoupons: { ...basePlugins.isDiscountCoupons, active: true }
2814
3031
  },
2815
3032
  ...menus?.length ? { menu: menus } : {},
2816
3033
  ...deliverable(base, ships),