@misiki/gocommerce-connector 0.28.0 → 0.29.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/README.md CHANGED
@@ -127,6 +127,7 @@ down stays best-effort: the storefront renders from its static record.
127
127
  | --- | --- |
128
128
  | product page, listings, search | `/api/products`, `/api/products/slug/{slug}` (an id or SKU also works) |
129
129
  | category pages and tree | `/api/categories`, `/api/categories/{slug}` — a category sells its descendants |
130
+ | the filter rail's categories | the counts from `/api/products?facets=1`, each with its ancestors from `/api/categories?flat=1`, in tree order and with its `depth`. A parent counts its whole subtree |
130
131
  | collections | `/api/collections`, `/api/collections/{slug}` |
131
132
  | featured / trending shelves | the collection with slug `featured` / `trending`; newest products when there is none |
132
133
  | product page extras | on the product from `/api/products/slug/{slug}` (D134): `highlights` and `freeGift` from the product's own metadata, `soldAtLeast` when the shop shows sold counts (null otherwise, never zero), and the product's videos after its pictures in `images` (and alone in `videos`), so the gallery plays them |
@@ -241,6 +242,10 @@ Each of these is a real gap, listed so nobody has to find it in production.
241
242
  vendor, product type, category attributes, price) need an engine that counts
242
243
  them (`GET /api/products?facets=1`, D130). Against an older one the filter
243
244
  rail is empty and a category page's attribute filters are not applied.
245
+ - **Category counts in a large shop.** The engine counts a listing's products
246
+ in at most 100 categories, the ones with the most products. The connector adds
247
+ those counts up to each parent, so in a shop with more categories a parent's
248
+ count misses the products of the categories the engine left out.
244
249
  - **Tax in the bag.** The engine's cart carries no tax or total; tax is computed
245
250
  when the order is placed. The bag shows subtotal − discount + delivery, and the
246
251
  order shows the real figures.
@@ -2469,13 +2469,19 @@ declare class ProductService extends CatalogService {
2469
2469
  }
2470
2470
  declare const productService: ProductService;
2471
2471
 
2472
+ type RailCategory = {
2473
+ name: string;
2474
+ slug: string;
2475
+ count: number;
2476
+ depth: number;
2477
+ };
2472
2478
  /**
2473
2479
  * The engine's counts in the shape the storefront's filter rail reads. Each
2474
2480
  * `allFilters` key is also the URL parameter the rail writes when a value is
2475
2481
  * ticked, and `searchWithUrl` reads it back: `vendor`, `product_type` and
2476
2482
  * `attributes.<handle>`. Tags go to the rail's own tag group, written as `tags`.
2477
2483
  */
2478
- declare function toStorefrontFacets(f?: ProductFacets | null): {
2484
+ declare function toStorefrontFacets(f?: ProductFacets | null, tree?: Category[]): {
2479
2485
  priceStat: {
2480
2486
  min: number;
2481
2487
  max: number;
@@ -2483,11 +2489,7 @@ declare function toStorefrontFacets(f?: ProductFacets | null): {
2483
2489
  min?: undefined;
2484
2490
  max?: undefined;
2485
2491
  };
2486
- categories: {
2487
- name: string;
2488
- slug: string;
2489
- count: number;
2490
- }[];
2492
+ categories: RailCategory[];
2491
2493
  tags: {
2492
2494
  name: string;
2493
2495
  count: number;
@@ -2520,11 +2522,7 @@ declare class SearchService extends CatalogService {
2520
2522
  min?: undefined;
2521
2523
  max?: undefined;
2522
2524
  };
2523
- categories: {
2524
- name: string;
2525
- slug: string;
2526
- count: number;
2527
- }[];
2525
+ categories: RailCategory[];
2528
2526
  tags: {
2529
2527
  name: string;
2530
2528
  count: number;
@@ -2548,11 +2546,7 @@ declare class SearchService extends CatalogService {
2548
2546
  min?: undefined;
2549
2547
  max?: undefined;
2550
2548
  };
2551
- categories: {
2552
- name: string;
2553
- slug: string;
2554
- count: number;
2555
- }[];
2549
+ categories: RailCategory[];
2556
2550
  tags: {
2557
2551
  name: string;
2558
2552
  count: number;
@@ -2719,11 +2713,7 @@ declare class SearchService extends CatalogService {
2719
2713
  min?: undefined;
2720
2714
  max?: undefined;
2721
2715
  };
2722
- categories: {
2723
- name: string;
2724
- slug: string;
2725
- count: number;
2726
- }[];
2716
+ categories: RailCategory[];
2727
2717
  tags: {
2728
2718
  name: string;
2729
2719
  count: number;
@@ -2469,13 +2469,19 @@ declare class ProductService extends CatalogService {
2469
2469
  }
2470
2470
  declare const productService: ProductService;
2471
2471
 
2472
+ type RailCategory = {
2473
+ name: string;
2474
+ slug: string;
2475
+ count: number;
2476
+ depth: number;
2477
+ };
2472
2478
  /**
2473
2479
  * The engine's counts in the shape the storefront's filter rail reads. Each
2474
2480
  * `allFilters` key is also the URL parameter the rail writes when a value is
2475
2481
  * ticked, and `searchWithUrl` reads it back: `vendor`, `product_type` and
2476
2482
  * `attributes.<handle>`. Tags go to the rail's own tag group, written as `tags`.
2477
2483
  */
2478
- declare function toStorefrontFacets(f?: ProductFacets | null): {
2484
+ declare function toStorefrontFacets(f?: ProductFacets | null, tree?: Category[]): {
2479
2485
  priceStat: {
2480
2486
  min: number;
2481
2487
  max: number;
@@ -2483,11 +2489,7 @@ declare function toStorefrontFacets(f?: ProductFacets | null): {
2483
2489
  min?: undefined;
2484
2490
  max?: undefined;
2485
2491
  };
2486
- categories: {
2487
- name: string;
2488
- slug: string;
2489
- count: number;
2490
- }[];
2492
+ categories: RailCategory[];
2491
2493
  tags: {
2492
2494
  name: string;
2493
2495
  count: number;
@@ -2520,11 +2522,7 @@ declare class SearchService extends CatalogService {
2520
2522
  min?: undefined;
2521
2523
  max?: undefined;
2522
2524
  };
2523
- categories: {
2524
- name: string;
2525
- slug: string;
2526
- count: number;
2527
- }[];
2525
+ categories: RailCategory[];
2528
2526
  tags: {
2529
2527
  name: string;
2530
2528
  count: number;
@@ -2548,11 +2546,7 @@ declare class SearchService extends CatalogService {
2548
2546
  min?: undefined;
2549
2547
  max?: undefined;
2550
2548
  };
2551
- categories: {
2552
- name: string;
2553
- slug: string;
2554
- count: number;
2555
- }[];
2549
+ categories: RailCategory[];
2556
2550
  tags: {
2557
2551
  name: string;
2558
2552
  count: number;
@@ -2719,11 +2713,7 @@ declare class SearchService extends CatalogService {
2719
2713
  min?: undefined;
2720
2714
  max?: undefined;
2721
2715
  };
2722
- categories: {
2723
- name: string;
2724
- slug: string;
2725
- count: number;
2726
- }[];
2716
+ categories: RailCategory[];
2727
2717
  tags: {
2728
2718
  name: string;
2729
2719
  count: number;
package/dist/index.cjs CHANGED
@@ -1593,7 +1593,23 @@ function attributesFrom(p) {
1593
1593
  return Object.keys(out).length ? out : void 0;
1594
1594
  }
1595
1595
  var counts = (values) => Object.fromEntries((values ?? []).map((v) => [v.value, v.count]));
1596
- function toStorefrontFacets(f) {
1596
+ function categoryFacets(counted, tree) {
1597
+ const byId = new Map(tree.map((c) => [c.id, c]));
1598
+ const totals = /* @__PURE__ */ new Map();
1599
+ for (const { id: id2, count } of counted) {
1600
+ for (let c = byId.get(id2); c; c = c.parent_id === null ? void 0 : byId.get(c.parent_id)) {
1601
+ totals.set(c.id, (totals.get(c.id) ?? 0) + count);
1602
+ }
1603
+ }
1604
+ const kept = tree.filter((c) => totals.has(c.id)).sort((a, b) => a.position - b.position || a.id - b.id);
1605
+ const parentOf = (c) => c.parent_id !== null && byId.has(c.parent_id) ? c.parent_id : null;
1606
+ const under = (parent) => kept.filter((c) => parentOf(c) === parent).flatMap((c) => [{ name: c.title, slug: c.slug, count: totals.get(c.id), depth: c.depth }, ...under(c.id)]);
1607
+ return [
1608
+ ...under(null),
1609
+ ...counted.filter((c) => !byId.has(c.id)).map((c) => ({ name: c.title, slug: c.slug, count: c.count, depth: 0 }))
1610
+ ];
1611
+ }
1612
+ function toStorefrontFacets(f, tree = []) {
1597
1613
  if (!f) return { priceStat: {}, categories: [], tags: [], allFilters: {} };
1598
1614
  const allFilters = {};
1599
1615
  const group = (key, values) => {
@@ -1604,7 +1620,7 @@ function toStorefrontFacets(f) {
1604
1620
  for (const [handle, values] of Object.entries(f.attributes ?? {})) group(`attributes.${handle}`, values);
1605
1621
  return {
1606
1622
  priceStat: f.price ? { min: toMajor(f.price.min), max: toMajor(f.price.max) } : {},
1607
- categories: (f.categories ?? []).map((c) => ({ name: c.title, slug: c.slug, count: c.count })),
1623
+ categories: categoryFacets(f.categories ?? [], tree),
1608
1624
  tags: (f.tags ?? []).map((t) => ({ name: t.value, count: t.count })),
1609
1625
  allFilters
1610
1626
  };
@@ -1637,13 +1653,14 @@ var SearchService = class extends CatalogService {
1637
1653
  productTypes: listParam(p, "product_type"),
1638
1654
  facets: true
1639
1655
  });
1656
+ const tree = res.facets?.categories?.length ? await this.facts.categories().catch(() => []) : [];
1640
1657
  return {
1641
1658
  data: res.data,
1642
1659
  count: res.count,
1643
1660
  totalPages: res.noOfPage,
1644
1661
  page: res.page,
1645
1662
  categoryHierarchy: res.categoryHierarchy,
1646
- facets: toStorefrontFacets(res.facets)
1663
+ facets: toStorefrontFacets(res.facets, tree)
1647
1664
  };
1648
1665
  } catch (err) {
1649
1666
  if (err?.status === 404) return this.emptyResult();