@aglyn/plugins-commerce 1.0.0-beta.198 → 1.0.0-beta.200

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.
Files changed (97) hide show
  1. package/package.json +13 -13
  2. package/src/lib/components/console/catalog-organization-card.component.js +48 -3
  3. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  4. package/src/lib/components/console/gift-cards-card.component.d.ts +9 -0
  5. package/src/lib/components/console/gift-cards-card.component.js +53 -28
  6. package/src/lib/components/console/gift-cards-card.component.js.map +1 -1
  7. package/src/lib/components/console/host-orders-card.component.d.ts +26 -0
  8. package/src/lib/components/console/host-orders-card.component.js +264 -194
  9. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  10. package/src/lib/components/console/pos-page.component.d.ts +14 -0
  11. package/src/lib/components/console/pos-page.component.js +86 -45
  12. package/src/lib/components/console/pos-page.component.js.map +1 -1
  13. package/src/lib/components/console/product-editor-dialog.component.js +30 -6
  14. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  15. package/src/lib/components/console/product-slugs.d.ts +43 -0
  16. package/src/lib/components/console/product-slugs.js +60 -0
  17. package/src/lib/components/console/product-slugs.js.map +1 -0
  18. package/src/lib/components/console/products-hub-card.component.d.ts +2 -2
  19. package/src/lib/components/console/products-hub-card.component.js +229 -282
  20. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  21. package/src/lib/components/console/products-hub-zone.component.d.ts +10 -5
  22. package/src/lib/components/console/products-hub-zone.component.js +32 -9
  23. package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
  24. package/src/lib/components/console/recovery-queue-card.component.d.ts +37 -5
  25. package/src/lib/components/console/recovery-queue-card.component.js +107 -86
  26. package/src/lib/components/console/recovery-queue-card.component.js.map +1 -1
  27. package/src/lib/components/console/reservations-card.component.js +15 -3
  28. package/src/lib/components/console/reservations-card.component.js.map +1 -1
  29. package/src/lib/components/console/smart-collections.d.ts +32 -0
  30. package/src/lib/components/console/smart-collections.js +57 -0
  31. package/src/lib/components/console/smart-collections.js.map +1 -0
  32. package/src/lib/components/console/stock-movements-card.component.d.ts +13 -4
  33. package/src/lib/components/console/stock-movements-card.component.js +142 -180
  34. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  35. package/src/lib/components/product-grid.d.ts +5 -0
  36. package/src/lib/components/product-grid.js +95 -34
  37. package/src/lib/components/product-grid.js.map +1 -1
  38. package/src/lib/constants/orders-list-query.d.ts +40 -0
  39. package/src/lib/constants/orders-list-query.js +205 -0
  40. package/src/lib/constants/orders-list-query.js.map +1 -0
  41. package/src/lib/constants/product-list-query.d.ts +42 -0
  42. package/src/lib/constants/product-list-query.js +217 -0
  43. package/src/lib/constants/product-list-query.js.map +1 -0
  44. package/src/lib/constants/stock-movement-query.d.ts +27 -0
  45. package/src/lib/constants/stock-movement-query.js +110 -0
  46. package/src/lib/constants/stock-movement-query.js.map +1 -0
  47. package/src/lib/constants/storefront-catalog-query.d.ts +103 -0
  48. package/src/lib/constants/storefront-catalog-query.js +312 -0
  49. package/src/lib/constants/storefront-catalog-query.js.map +1 -0
  50. package/src/lib/model/checkout-recovery.d.ts +37 -0
  51. package/src/lib/model/checkout-recovery.js +44 -0
  52. package/src/lib/model/checkout-recovery.js.map +1 -0
  53. package/src/lib/model/commerce.d.ts +80 -0
  54. package/src/lib/model/commerce.js +67 -6
  55. package/src/lib/model/commerce.js.map +1 -1
  56. package/src/lib/model/gift-card-search.d.ts +24 -0
  57. package/src/lib/model/gift-card-search.js +48 -0
  58. package/src/lib/model/gift-card-search.js.map +1 -0
  59. package/src/lib/model/index.d.ts +1 -0
  60. package/src/lib/model/index.js +1 -0
  61. package/src/lib/model/index.js.map +1 -1
  62. package/src/lib/model/order-list-fields.d.ts +80 -0
  63. package/src/lib/model/order-list-fields.js +112 -0
  64. package/src/lib/model/order-list-fields.js.map +1 -0
  65. package/src/lib/server/billing-webhook.js +108 -89
  66. package/src/lib/server/billing-webhook.js.map +1 -1
  67. package/src/lib/server/cancel-order.js +6 -6
  68. package/src/lib/server/cancel-order.js.map +1 -1
  69. package/src/lib/server/cart-checkout.js +6 -0
  70. package/src/lib/server/cart-checkout.js.map +1 -1
  71. package/src/lib/server/catalog.d.ts +46 -30
  72. package/src/lib/server/catalog.js +492 -170
  73. package/src/lib/server/catalog.js.map +1 -1
  74. package/src/lib/server/collection-membership.d.ts +35 -0
  75. package/src/lib/server/collection-membership.js +172 -0
  76. package/src/lib/server/collection-membership.js.map +1 -0
  77. package/src/lib/server/draft-order.js +3 -2
  78. package/src/lib/server/draft-order.js.map +1 -1
  79. package/src/lib/server/gift-cards.js +3 -0
  80. package/src/lib/server/gift-cards.js.map +1 -1
  81. package/src/lib/server/member-name-search.d.ts +17 -0
  82. package/src/lib/server/member-name-search.js +23 -1
  83. package/src/lib/server/member-name-search.js.map +1 -1
  84. package/src/lib/server/membership-account.js +7 -3
  85. package/src/lib/server/membership-account.js.map +1 -1
  86. package/src/lib/server/membership-register.js +3 -1
  87. package/src/lib/server/membership-register.js.map +1 -1
  88. package/src/lib/server/pos-order.js +6 -4
  89. package/src/lib/server/pos-order.js.map +1 -1
  90. package/src/lib/server/process-abandoned.js +14 -5
  91. package/src/lib/server/process-abandoned.js.map +1 -1
  92. package/src/lib/server/reserve-stock.js +3 -4
  93. package/src/lib/server/reserve-stock.js.map +1 -1
  94. package/src/lib/server/site-page-enricher.js +3 -3
  95. package/src/lib/server/site-page-enricher.js.map +1 -1
  96. package/src/lib/server.js +4 -0
  97. package/src/lib/server.js.map +1 -1
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import type { PluginApiHandler } from '@aglyn/aglyn/server';
18
+ import { type ListQueryRefusal } from '@aglyn/shared-ui-jsx/const/list-query-plan';
18
19
  import * as CommerceModel from '../model';
19
20
  export interface PublicCatalogItem {
20
21
  id: string;
@@ -40,16 +41,11 @@ export interface PublicCatalogPriceBounds {
40
41
  maxCents: number;
41
42
  }
42
43
  /**
43
- * Displayed price in cents (AGL-564): the low end of the variant range —
44
- * the number grid cards render (`$X` / `From $X`) — so price filtering
45
- * matches what visitors see.
44
+ * A control the query could not apply, and why — the plan's own refusal,
45
+ * which the grid names through `listQueryRefusals` with the declaration's
46
+ * fields and the categories it shows.
46
47
  */
47
- export declare function displayedPriceCents(product: Pick<CommerceModel.HostProduct, 'variants'>): number;
48
- /**
49
- * Case-insensitive catalog search (AGL-561): matches the product name,
50
- * description, or any tag. An empty/blank query matches everything.
51
- */
52
- export declare function matchesCatalogQuery(product: Pick<CommerceModel.HostProduct, 'name' | 'description' | 'tags'>, query: string): boolean;
48
+ export type PublicCatalogRefusal = ListQueryRefusal;
53
49
  /** A catalog query, already parsed and bounded. */
54
50
  export interface PublicCatalogQuery {
55
51
  hostId: string;
@@ -58,9 +54,11 @@ export interface PublicCatalogQuery {
58
54
  categoryId?: string;
59
55
  categorySlug?: string;
60
56
  tag?: string;
61
- /** Free-text search over name, description and tags. */
57
+ /** Search: the first word, matched as a word prefix of the product name. */
62
58
  query?: string;
63
59
  type?: CommerceModel.ProductType | '';
60
+ /** The In stock chip: only products a card would not mark sold out. */
61
+ inStock?: boolean;
64
62
  /** Explicit id list in the given order (wishlist rendering, AGL-297). */
65
63
  ids?: string[];
66
64
  minPriceCents?: number;
@@ -68,7 +66,8 @@ export interface PublicCatalogQuery {
68
66
  sort?: string;
69
67
  /** Page size, 1–100. */
70
68
  limit?: number;
71
- offset?: number;
69
+ /** The `nextCursor` a previous page returned — continue after it. */
70
+ after?: string;
72
71
  /** Include category + price facets in the result. */
73
72
  facets?: boolean;
74
73
  /**
@@ -80,42 +79,59 @@ export interface PublicCatalogQuery {
80
79
  /**
81
80
  * Reads shared by every catalog query in ONE render, for ONE host.
82
81
  *
83
- * The products read does not vary with the query — the whole catalog is
84
- * fetched and then filtered in memory by collection, category, tag, price and
85
- * search text. A page carrying four product grids therefore issued four
86
- * identical 500-document reads and threw three of them away.
87
- *
88
- * This shares the READ, never the RESULT. Each grid still filters and sorts
89
- * the shared snapshot independently, because a collection-scoped grid and an
90
- * all-products grid on the same page must not receive each other's items.
82
+ * Two grids on one page asking the SAME question share one answer, and every
83
+ * grid that shows category chips shares one read of the taxonomy. A grid
84
+ * asking a different question — another collection, another sort — runs its
85
+ * own query, because each query now reads only the page it returns rather
86
+ * than the whole catalog (AGL-3321).
91
87
  *
92
- * Scoped to one host and one render deliberately: it holds a promise, not
88
+ * Scoped to one host and one render deliberately: it holds promises, not
93
89
  * data, so nothing is cached across requests and no staleness window opens.
94
90
  * Reusing a scope for a second host would serve that host the first one's
95
91
  * catalog, which is why it is created per render rather than per module.
96
92
  */
97
93
  export interface CatalogReadScope {
98
- products?: Promise<FirebaseFirestore.QuerySnapshot>;
99
94
  categories?: Promise<FirebaseFirestore.QuerySnapshot>;
95
+ results?: Map<string, Promise<PublicCatalogResult>>;
100
96
  }
101
97
  /** A fresh read scope. One per render, never reused across hosts. */
102
98
  export declare function createCatalogReadScope(): CatalogReadScope;
103
99
  /** What both the API route and the SSR seed hand to a product grid. */
104
100
  export interface PublicCatalogResult {
105
101
  items: PublicCatalogItem[];
106
- nextOffset?: number;
102
+ /** Pass back as `after` for the next page; absent on the last one. */
103
+ nextCursor?: string;
107
104
  categories?: PublicCatalogCategory[];
108
105
  priceBounds?: PublicCatalogPriceBounds;
106
+ /** Controls in force that the query could not apply (AGL-3321). */
107
+ refused?: PublicCatalogRefusal[];
108
+ /** Said about what WAS applied, e.g. that search reads one word. */
109
+ notices?: string[];
109
110
  }
110
111
  /**
111
- * Public catalog listing (AGL-291): active products for storefront
112
- * blocks — filterable by collection/category slug or tag, sortable,
113
- * capped at 100 items per request. Storefront catalog UX (AGL-561)
114
- * adds text search, a product-type filter, offset paging (for Load
115
- * more), and facets for filter chips. The price-range filter (AGL-564)
116
- * bounds on the displayed price and reports `priceBounds`.
117
- * Read-only public data; prices here are display-only (charges always
118
- * come from the docs server-side).
112
+ * Public catalog listing (AGL-291): active products for storefront blocks —
113
+ * a collection, a category or a tag, searched, filtered by type and price,
114
+ * sorted, and paged by cursor (AGL-561, AGL-564).
115
+ *
116
+ * EVERY CONTROL IS ON THE QUERY (AGL-3321). This used to read `limit(500)`
117
+ * products and narrow them in memory, so a catalog past five hundred answered
118
+ * every search, chip and slider from an arbitrary five hundred of them. Now:
119
+ *
120
+ * - the catalog, a category or a tag — ONE query built by the list query
121
+ * plan (`STOREFRONT_CATALOG_DECLARATION`), paged by its own cursor;
122
+ * - a SMART collection whose rules a query can hold — the same query, with
123
+ * the rules as its scope (`smartCollectionScope`);
124
+ * - a MANUAL collection, or an explicit id list — read whole by id, which
125
+ * is a complete set, and answered over all of it;
126
+ * - a smart collection whose rules no query can hold (a NOT, an OR, a name
127
+ * rule, a price over) — the same query, scoped by the membership every
128
+ * product writer stores (`collectionIds array-contains <id>`), which the
129
+ * collection-membership route re-stamps whenever the rules change.
130
+ *
131
+ * What one query cannot hold — two array clauses, two ranges — is refused by
132
+ * name in `refused` and not applied, never applied to some rows and not
133
+ * others. Read-only public data; prices here are display-only (charges
134
+ * always come from the docs server-side).
119
135
  *
120
136
  * Extracted from the handler (AGL-659) so the site-page enricher seeds a
121
137
  * grid's first page through THIS function rather than a reimplementation