@aglyn/plugins-commerce 1.0.0-beta.143

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 (417) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +10 -0
  3. package/package.json +57 -0
  4. package/src/index.d.ts +38 -0
  5. package/src/index.js +38 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/account.d.ts +31 -0
  8. package/src/lib/components/account.js +645 -0
  9. package/src/lib/components/account.js.map +1 -0
  10. package/src/lib/components/cart.d.ts +38 -0
  11. package/src/lib/components/cart.js +851 -0
  12. package/src/lib/components/cart.js.map +1 -0
  13. package/src/lib/components/commerce-console-page.d.ts +32 -0
  14. package/src/lib/components/commerce-console-page.js +296 -0
  15. package/src/lib/components/commerce-console-page.js.map +1 -0
  16. package/src/lib/components/commerce-console-sections.d.ts +34 -0
  17. package/src/lib/components/commerce-console-sections.js +62 -0
  18. package/src/lib/components/commerce-console-sections.js.map +1 -0
  19. package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
  20. package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
  21. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
  22. package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
  23. package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
  24. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
  25. package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
  26. package/src/lib/components/console/commerce-glance-card.component.js +340 -0
  27. package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
  28. package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
  29. package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
  30. package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
  31. package/src/lib/components/console/discounts-card.component.d.ts +14 -0
  32. package/src/lib/components/console/discounts-card.component.js +443 -0
  33. package/src/lib/components/console/discounts-card.component.js.map +1 -0
  34. package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
  35. package/src/lib/components/console/entitlement-gate.component.js +115 -0
  36. package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
  37. package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
  38. package/src/lib/components/console/gift-cards-card.component.js +379 -0
  39. package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
  40. package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
  41. package/src/lib/components/console/host-coupons-card.component.js +252 -0
  42. package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
  43. package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
  44. package/src/lib/components/console/host-orders-card.component.js +861 -0
  45. package/src/lib/components/console/host-orders-card.component.js.map +1 -0
  46. package/src/lib/components/console/locations-card.component.d.ts +14 -0
  47. package/src/lib/components/console/locations-card.component.js +256 -0
  48. package/src/lib/components/console/locations-card.component.js.map +1 -0
  49. package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
  50. package/src/lib/components/console/member-posts-card.component.js +283 -0
  51. package/src/lib/components/console/member-posts-card.component.js.map +1 -0
  52. package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
  53. package/src/lib/components/console/newest-site-users-card.component.js +126 -0
  54. package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
  55. package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
  56. package/src/lib/components/console/order-detail-dialog.component.js +976 -0
  57. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
  58. package/src/lib/components/console/paid-media.d.ts +127 -0
  59. package/src/lib/components/console/paid-media.js +397 -0
  60. package/src/lib/components/console/paid-media.js.map +1 -0
  61. package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
  62. package/src/lib/components/console/payments-settings-card.component.js +295 -0
  63. package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
  64. package/src/lib/components/console/pos-page.component.d.ts +13 -0
  65. package/src/lib/components/console/pos-page.component.js +916 -0
  66. package/src/lib/components/console/pos-page.component.js.map +1 -0
  67. package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
  68. package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
  69. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
  70. package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
  71. package/src/lib/components/console/products-hub-card.component.js +1280 -0
  72. package/src/lib/components/console/products-hub-card.component.js.map +1 -0
  73. package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
  74. package/src/lib/components/console/products-hub-zone.component.js +200 -0
  75. package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
  76. package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
  77. package/src/lib/components/console/recovery-queue-card.component.js +262 -0
  78. package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
  79. package/src/lib/components/console/registers-card.component.d.ts +21 -0
  80. package/src/lib/components/console/registers-card.component.js +296 -0
  81. package/src/lib/components/console/registers-card.component.js.map +1 -0
  82. package/src/lib/components/console/reservations-card.component.d.ts +14 -0
  83. package/src/lib/components/console/reservations-card.component.js +650 -0
  84. package/src/lib/components/console/reservations-card.component.js.map +1 -0
  85. package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
  86. package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
  87. package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
  88. package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
  89. package/src/lib/components/console/shipping-settings-card.component.js +560 -0
  90. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
  91. package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
  92. package/src/lib/components/console/stock-movements-card.component.js +333 -0
  93. package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
  94. package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
  95. package/src/lib/components/console/store-settings-card.component.js +300 -0
  96. package/src/lib/components/console/store-settings-card.component.js.map +1 -0
  97. package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
  98. package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
  99. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
  100. package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
  101. package/src/lib/components/console/suppliers-card.component.js +328 -0
  102. package/src/lib/components/console/suppliers-card.component.js.map +1 -0
  103. package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
  104. package/src/lib/components/console/tax-settings-card.component.js +473 -0
  105. package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
  106. package/src/lib/components/gate.d.ts +39 -0
  107. package/src/lib/components/gate.js +202 -0
  108. package/src/lib/components/gate.js.map +1 -0
  109. package/src/lib/components/gated-video.d.ts +40 -0
  110. package/src/lib/components/gated-video.js +366 -0
  111. package/src/lib/components/gated-video.js.map +1 -0
  112. package/src/lib/components/member-feed.d.ts +32 -0
  113. package/src/lib/components/member-feed.js +198 -0
  114. package/src/lib/components/member-feed.js.map +1 -0
  115. package/src/lib/components/member-recovery.d.ts +35 -0
  116. package/src/lib/components/member-recovery.js +313 -0
  117. package/src/lib/components/member-recovery.js.map +1 -0
  118. package/src/lib/components/member-signin.d.ts +35 -0
  119. package/src/lib/components/member-signin.js +257 -0
  120. package/src/lib/components/member-signin.js.map +1 -0
  121. package/src/lib/components/member-signup.d.ts +34 -0
  122. package/src/lib/components/member-signup.js +287 -0
  123. package/src/lib/components/member-signup.js.map +1 -0
  124. package/src/lib/components/newsletter-signup.d.ts +39 -0
  125. package/src/lib/components/newsletter-signup.js +229 -0
  126. package/src/lib/components/newsletter-signup.js.map +1 -0
  127. package/src/lib/components/product-detail.d.ts +38 -0
  128. package/src/lib/components/product-detail.js +1022 -0
  129. package/src/lib/components/product-detail.js.map +1 -0
  130. package/src/lib/components/product-grid.d.ts +67 -0
  131. package/src/lib/components/product-grid.js +909 -0
  132. package/src/lib/components/product-grid.js.map +1 -0
  133. package/src/lib/components/product-reviews.d.ts +32 -0
  134. package/src/lib/components/product-reviews.js +349 -0
  135. package/src/lib/components/product-reviews.js.map +1 -0
  136. package/src/lib/components/related-products.d.ts +33 -0
  137. package/src/lib/components/related-products.js +232 -0
  138. package/src/lib/components/related-products.js.map +1 -0
  139. package/src/lib/components/reservation-widget.d.ts +33 -0
  140. package/src/lib/components/reservation-widget.js +418 -0
  141. package/src/lib/components/reservation-widget.js.map +1 -0
  142. package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
  143. package/src/lib/components/storefront-payment-element-fallback.js +51 -0
  144. package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
  145. package/src/lib/components/storefront-payment-element.d.ts +78 -0
  146. package/src/lib/components/storefront-payment-element.js +156 -0
  147. package/src/lib/components/storefront-payment-element.js.map +1 -0
  148. package/src/lib/components/wishlist.d.ts +46 -0
  149. package/src/lib/components/wishlist.js +304 -0
  150. package/src/lib/components/wishlist.js.map +1 -0
  151. package/src/lib/constants/bundle-common.d.ts +18 -0
  152. package/src/lib/constants/bundle-common.js +18 -0
  153. package/src/lib/constants/bundle-common.js.map +1 -0
  154. package/src/lib/constants/product-filters.d.ts +35 -0
  155. package/src/lib/constants/product-filters.js +109 -0
  156. package/src/lib/constants/product-filters.js.map +1 -0
  157. package/src/lib/model/commerce-cart.d.ts +52 -0
  158. package/src/lib/model/commerce-cart.js +102 -0
  159. package/src/lib/model/commerce-cart.js.map +1 -0
  160. package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
  161. package/src/lib/model/commerce-connect-transfer.js +231 -0
  162. package/src/lib/model/commerce-connect-transfer.js.map +1 -0
  163. package/src/lib/model/commerce-discounts.d.ts +164 -0
  164. package/src/lib/model/commerce-discounts.js +231 -0
  165. package/src/lib/model/commerce-discounts.js.map +1 -0
  166. package/src/lib/model/commerce-dispute.d.ts +124 -0
  167. package/src/lib/model/commerce-dispute.js +225 -0
  168. package/src/lib/model/commerce-dispute.js.map +1 -0
  169. package/src/lib/model/commerce-gift-cards.d.ts +107 -0
  170. package/src/lib/model/commerce-gift-cards.js +121 -0
  171. package/src/lib/model/commerce-gift-cards.js.map +1 -0
  172. package/src/lib/model/commerce-io.d.ts +36 -0
  173. package/src/lib/model/commerce-io.js +245 -0
  174. package/src/lib/model/commerce-io.js.map +1 -0
  175. package/src/lib/model/commerce-orders.d.ts +1040 -0
  176. package/src/lib/model/commerce-orders.js +1022 -0
  177. package/src/lib/model/commerce-orders.js.map +1 -0
  178. package/src/lib/model/commerce-promotions.d.ts +188 -0
  179. package/src/lib/model/commerce-promotions.js +199 -0
  180. package/src/lib/model/commerce-promotions.js.map +1 -0
  181. package/src/lib/model/commerce-reservations.d.ts +175 -0
  182. package/src/lib/model/commerce-reservations.js +157 -0
  183. package/src/lib/model/commerce-reservations.js.map +1 -0
  184. package/src/lib/model/commerce-shipping.d.ts +316 -0
  185. package/src/lib/model/commerce-shipping.js +484 -0
  186. package/src/lib/model/commerce-shipping.js.map +1 -0
  187. package/src/lib/model/commerce-stock-holds.d.ts +199 -0
  188. package/src/lib/model/commerce-stock-holds.js +190 -0
  189. package/src/lib/model/commerce-stock-holds.js.map +1 -0
  190. package/src/lib/model/commerce-subscription-status.d.ts +67 -0
  191. package/src/lib/model/commerce-subscription-status.js +76 -0
  192. package/src/lib/model/commerce-subscription-status.js.map +1 -0
  193. package/src/lib/model/commerce-tax-decision.d.ts +222 -0
  194. package/src/lib/model/commerce-tax-decision.js +165 -0
  195. package/src/lib/model/commerce-tax-decision.js.map +1 -0
  196. package/src/lib/model/commerce-tax.d.ts +176 -0
  197. package/src/lib/model/commerce-tax.js +92 -0
  198. package/src/lib/model/commerce-tax.js.map +1 -0
  199. package/src/lib/model/commerce.d.ts +551 -0
  200. package/src/lib/model/commerce.js +739 -0
  201. package/src/lib/model/commerce.js.map +1 -0
  202. package/src/lib/model/index.d.ts +40 -0
  203. package/src/lib/model/index.js +40 -0
  204. package/src/lib/model/index.js.map +1 -0
  205. package/src/lib/model/order-figures.d.ts +48 -0
  206. package/src/lib/model/order-figures.js +74 -0
  207. package/src/lib/model/order-figures.js.map +1 -0
  208. package/src/lib/model/plugin-permissions.d.ts +23 -0
  209. package/src/lib/model/plugin-permissions.js +34 -0
  210. package/src/lib/model/plugin-permissions.js.map +1 -0
  211. package/src/lib/model/purchase-analytics.d.ts +186 -0
  212. package/src/lib/model/purchase-analytics.js +216 -0
  213. package/src/lib/model/purchase-analytics.js.map +1 -0
  214. package/src/lib/plugin-config.d.ts +62 -0
  215. package/src/lib/plugin-config.js +78 -0
  216. package/src/lib/plugin-config.js.map +1 -0
  217. package/src/lib/plugin.d.ts +28 -0
  218. package/src/lib/plugin.js +147 -0
  219. package/src/lib/plugin.js.map +1 -0
  220. package/src/lib/server/billing-webhook.d.ts +26 -0
  221. package/src/lib/server/billing-webhook.js +4011 -0
  222. package/src/lib/server/billing-webhook.js.map +1 -0
  223. package/src/lib/server/cancel-order.d.ts +87 -0
  224. package/src/lib/server/cancel-order.js +368 -0
  225. package/src/lib/server/cancel-order.js.map +1 -0
  226. package/src/lib/server/cart-checkout.d.ts +25 -0
  227. package/src/lib/server/cart-checkout.js +976 -0
  228. package/src/lib/server/cart-checkout.js.map +1 -0
  229. package/src/lib/server/cart-cookie.d.ts +32 -0
  230. package/src/lib/server/cart-cookie.js +77 -0
  231. package/src/lib/server/cart-cookie.js.map +1 -0
  232. package/src/lib/server/cart.d.ts +34 -0
  233. package/src/lib/server/cart.js +181 -0
  234. package/src/lib/server/cart.js.map +1 -0
  235. package/src/lib/server/catalog.d.ts +127 -0
  236. package/src/lib/server/catalog.js +277 -0
  237. package/src/lib/server/catalog.js.map +1 -0
  238. package/src/lib/server/checkout.d.ts +36 -0
  239. package/src/lib/server/checkout.js +915 -0
  240. package/src/lib/server/checkout.js.map +1 -0
  241. package/src/lib/server/connect.d.ts +26 -0
  242. package/src/lib/server/connect.js +238 -0
  243. package/src/lib/server/connect.js.map +1 -0
  244. package/src/lib/server/contact-refund.d.ts +117 -0
  245. package/src/lib/server/contact-refund.js +196 -0
  246. package/src/lib/server/contact-refund.js.map +1 -0
  247. package/src/lib/server/download.d.ts +39 -0
  248. package/src/lib/server/download.js +206 -0
  249. package/src/lib/server/download.js.map +1 -0
  250. package/src/lib/server/draft-order.d.ts +26 -0
  251. package/src/lib/server/draft-order.js +706 -0
  252. package/src/lib/server/draft-order.js.map +1 -0
  253. package/src/lib/server/feed.d.ts +24 -0
  254. package/src/lib/server/feed.js +59 -0
  255. package/src/lib/server/feed.js.map +1 -0
  256. package/src/lib/server/fulfill-order.d.ts +97 -0
  257. package/src/lib/server/fulfill-order.js +235 -0
  258. package/src/lib/server/fulfill-order.js.map +1 -0
  259. package/src/lib/server/gate.d.ts +36 -0
  260. package/src/lib/server/gate.js +112 -0
  261. package/src/lib/server/gate.js.map +1 -0
  262. package/src/lib/server/gift-cards.d.ts +42 -0
  263. package/src/lib/server/gift-cards.js +219 -0
  264. package/src/lib/server/gift-cards.js.map +1 -0
  265. package/src/lib/server/low-stock.d.ts +49 -0
  266. package/src/lib/server/low-stock.js +60 -0
  267. package/src/lib/server/low-stock.js.map +1 -0
  268. package/src/lib/server/manual-tax-rate.d.ts +82 -0
  269. package/src/lib/server/manual-tax-rate.js +113 -0
  270. package/src/lib/server/manual-tax-rate.js.map +1 -0
  271. package/src/lib/server/member-feed.d.ts +24 -0
  272. package/src/lib/server/member-feed.js +72 -0
  273. package/src/lib/server/member-feed.js.map +1 -0
  274. package/src/lib/server/member-name-search.d.ts +37 -0
  275. package/src/lib/server/member-name-search.js +42 -0
  276. package/src/lib/server/member-name-search.js.map +1 -0
  277. package/src/lib/server/member-post.d.ts +23 -0
  278. package/src/lib/server/member-post.js +166 -0
  279. package/src/lib/server/member-post.js.map +1 -0
  280. package/src/lib/server/membership-account.d.ts +37 -0
  281. package/src/lib/server/membership-account.js +148 -0
  282. package/src/lib/server/membership-account.js.map +1 -0
  283. package/src/lib/server/membership-admin-password.d.ts +33 -0
  284. package/src/lib/server/membership-admin-password.js +202 -0
  285. package/src/lib/server/membership-admin-password.js.map +1 -0
  286. package/src/lib/server/membership-content.d.ts +23 -0
  287. package/src/lib/server/membership-content.js +105 -0
  288. package/src/lib/server/membership-content.js.map +1 -0
  289. package/src/lib/server/membership-login.d.ts +19 -0
  290. package/src/lib/server/membership-login.js +137 -0
  291. package/src/lib/server/membership-login.js.map +1 -0
  292. package/src/lib/server/membership-logout.d.ts +19 -0
  293. package/src/lib/server/membership-logout.js +35 -0
  294. package/src/lib/server/membership-logout.js.map +1 -0
  295. package/src/lib/server/membership-recover.d.ts +60 -0
  296. package/src/lib/server/membership-recover.js +244 -0
  297. package/src/lib/server/membership-recover.js.map +1 -0
  298. package/src/lib/server/membership-register.d.ts +22 -0
  299. package/src/lib/server/membership-register.js +241 -0
  300. package/src/lib/server/membership-register.js.map +1 -0
  301. package/src/lib/server/membership-reset.d.ts +26 -0
  302. package/src/lib/server/membership-reset.js +88 -0
  303. package/src/lib/server/membership-reset.js.map +1 -0
  304. package/src/lib/server/membership-wishlist.d.ts +23 -0
  305. package/src/lib/server/membership-wishlist.js +89 -0
  306. package/src/lib/server/membership-wishlist.js.map +1 -0
  307. package/src/lib/server/membership.d.ts +96 -0
  308. package/src/lib/server/membership.js +222 -0
  309. package/src/lib/server/membership.js.map +1 -0
  310. package/src/lib/server/native-checkout.d.ts +170 -0
  311. package/src/lib/server/native-checkout.js +193 -0
  312. package/src/lib/server/native-checkout.js.map +1 -0
  313. package/src/lib/server/newsletter.d.ts +23 -0
  314. package/src/lib/server/newsletter.js +323 -0
  315. package/src/lib/server/newsletter.js.map +1 -0
  316. package/src/lib/server/notify-restock.d.ts +22 -0
  317. package/src/lib/server/notify-restock.js +84 -0
  318. package/src/lib/server/notify-restock.js.map +1 -0
  319. package/src/lib/server/order-analytics.d.ts +134 -0
  320. package/src/lib/server/order-analytics.js +263 -0
  321. package/src/lib/server/order-analytics.js.map +1 -0
  322. package/src/lib/server/order-figures.d.ts +33 -0
  323. package/src/lib/server/order-figures.js +220 -0
  324. package/src/lib/server/order-figures.js.map +1 -0
  325. package/src/lib/server/paid-media-delivery.d.ts +173 -0
  326. package/src/lib/server/paid-media-delivery.js +212 -0
  327. package/src/lib/server/paid-media-delivery.js.map +1 -0
  328. package/src/lib/server/pos-order.d.ts +54 -0
  329. package/src/lib/server/pos-order.js +1137 -0
  330. package/src/lib/server/pos-order.js.map +1 -0
  331. package/src/lib/server/process-abandoned.d.ts +54 -0
  332. package/src/lib/server/process-abandoned.js +222 -0
  333. package/src/lib/server/process-abandoned.js.map +1 -0
  334. package/src/lib/server/process-restock.d.ts +42 -0
  335. package/src/lib/server/process-restock.js +219 -0
  336. package/src/lib/server/process-restock.js.map +1 -0
  337. package/src/lib/server/product-card.d.ts +29 -0
  338. package/src/lib/server/product-card.js +54 -0
  339. package/src/lib/server/product-card.js.map +1 -0
  340. package/src/lib/server/product.d.ts +70 -0
  341. package/src/lib/server/product.js +105 -0
  342. package/src/lib/server/product.js.map +1 -0
  343. package/src/lib/server/promotion-hold.d.ts +144 -0
  344. package/src/lib/server/promotion-hold.js +174 -0
  345. package/src/lib/server/promotion-hold.js.map +1 -0
  346. package/src/lib/server/reconcile-stock.d.ts +106 -0
  347. package/src/lib/server/reconcile-stock.js +349 -0
  348. package/src/lib/server/reconcile-stock.js.map +1 -0
  349. package/src/lib/server/refund.d.ts +45 -0
  350. package/src/lib/server/refund.js +607 -0
  351. package/src/lib/server/refund.js.map +1 -0
  352. package/src/lib/server/related.d.ts +24 -0
  353. package/src/lib/server/related.js +104 -0
  354. package/src/lib/server/related.js.map +1 -0
  355. package/src/lib/server/reservation-availability.d.ts +23 -0
  356. package/src/lib/server/reservation-availability.js +111 -0
  357. package/src/lib/server/reservation-availability.js.map +1 -0
  358. package/src/lib/server/reserve-stock.d.ts +156 -0
  359. package/src/lib/server/reserve-stock.js +146 -0
  360. package/src/lib/server/reserve-stock.js.map +1 -0
  361. package/src/lib/server/reserve.d.ts +25 -0
  362. package/src/lib/server/reserve.js +426 -0
  363. package/src/lib/server/reserve.js.map +1 -0
  364. package/src/lib/server/restock-flag.d.ts +202 -0
  365. package/src/lib/server/restock-flag.js +449 -0
  366. package/src/lib/server/restock-flag.js.map +1 -0
  367. package/src/lib/server/reviews.d.ts +51 -0
  368. package/src/lib/server/reviews.js +132 -0
  369. package/src/lib/server/reviews.js.map +1 -0
  370. package/src/lib/server/site-page-enricher.d.ts +42 -0
  371. package/src/lib/server/site-page-enricher.js +149 -0
  372. package/src/lib/server/site-page-enricher.js.map +1 -0
  373. package/src/lib/server/site-page-resolver.d.ts +26 -0
  374. package/src/lib/server/site-page-resolver.js +223 -0
  375. package/src/lib/server/site-page-resolver.js.map +1 -0
  376. package/src/lib/server/stock-hold.d.ts +127 -0
  377. package/src/lib/server/stock-hold.js +258 -0
  378. package/src/lib/server/stock-hold.js.map +1 -0
  379. package/src/lib/server/storefront-tax-record.d.ts +22 -0
  380. package/src/lib/server/storefront-tax-record.js +218 -0
  381. package/src/lib/server/storefront-tax-record.js.map +1 -0
  382. package/src/lib/server/storefront-tax.d.ts +197 -0
  383. package/src/lib/server/storefront-tax.js +245 -0
  384. package/src/lib/server/storefront-tax.js.map +1 -0
  385. package/src/lib/server/stream.d.ts +25 -0
  386. package/src/lib/server/stream.js +191 -0
  387. package/src/lib/server/stream.js.map +1 -0
  388. package/src/lib/server/subscription-portal.d.ts +24 -0
  389. package/src/lib/server/subscription-portal.js +91 -0
  390. package/src/lib/server/subscription-portal.js.map +1 -0
  391. package/src/lib/server/supplier-outbox.d.ts +190 -0
  392. package/src/lib/server/supplier-outbox.js +342 -0
  393. package/src/lib/server/supplier-outbox.js.map +1 -0
  394. package/src/lib/server/supplier-update.d.ts +23 -0
  395. package/src/lib/server/supplier-update.js +289 -0
  396. package/src/lib/server/supplier-update.js.map +1 -0
  397. package/src/lib/server/tax-profile.d.ts +29 -0
  398. package/src/lib/server/tax-profile.js +40 -0
  399. package/src/lib/server/tax-profile.js.map +1 -0
  400. package/src/lib/server.d.ts +32 -0
  401. package/src/lib/server.js +311 -0
  402. package/src/lib/server.js.map +1 -0
  403. package/src/lib/site.d.ts +27 -0
  404. package/src/lib/site.js +134 -0
  405. package/src/lib/site.js.map +1 -0
  406. package/src/lib/utils/escape-html.d.ts +41 -0
  407. package/src/lib/utils/escape-html.js +41 -0
  408. package/src/lib/utils/escape-html.js.map +1 -0
  409. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  410. package/src/lib/utils/generate-preset-id.js +25 -0
  411. package/src/lib/utils/generate-preset-id.js.map +1 -0
  412. package/src/lib/utils/member-continue.d.ts +45 -0
  413. package/src/lib/utils/member-continue.js +49 -0
  414. package/src/lib/utils/member-continue.js.map +1 -0
  415. package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
  416. package/src/lib/utils/use-storefront-purchase-event.js +142 -0
  417. package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import * as Aglyn from "@aglyn/aglyn/server";
17
+ import * as CommerceModel from "../model/index.js";
18
+ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
19
+ /**
20
+ * Approved reviews for a product, newest first, plus their aggregate.
21
+ *
22
+ * Extracted from the handler (AGL-686) so the site-page resolver can nest
23
+ * `aggregateRating` inside the server-rendered `Product` node. Schema.org
24
+ * wants it as a PROPERTY of the product; the reviews block was emitting a
25
+ * free-standing `AggregateRating` node alongside it, which is orphaned and
26
+ * ignored. One reader means the rating in the structured data and the rating
27
+ * on the page cannot disagree.
28
+ */ export async function readProductReviews(hostId, productId) {
29
+ const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId);
30
+ const reviewsSnapshot = await hostRef.collection('reviews').where('productId', '==', productId).where('status', '==', 'approved').limit(100).get();
31
+ const reviews = reviewsSnapshot.docs.map((docSnapshot)=>{
32
+ var _docSnapshot_get, _docSnapshot_get1, _docSnapshot_get2, _docSnapshot_get3, _docSnapshot_get4;
33
+ return {
34
+ id: docSnapshot.id,
35
+ rating: Number((_docSnapshot_get = docSnapshot.get('rating')) != null ? _docSnapshot_get : 0),
36
+ body: String((_docSnapshot_get1 = docSnapshot.get('body')) != null ? _docSnapshot_get1 : ''),
37
+ authorName: String((_docSnapshot_get2 = docSnapshot.get('authorName')) != null ? _docSnapshot_get2 : 'Anonymous'),
38
+ verified: Boolean(docSnapshot.get('verified')),
39
+ reply: (_docSnapshot_get3 = docSnapshot.get('reply')) != null ? _docSnapshot_get3 : null,
40
+ createdAtMs: Number((_docSnapshot_get4 = docSnapshot.get('createdAtMs')) != null ? _docSnapshot_get4 : 0)
41
+ };
42
+ }).sort((a, b)=>b.createdAtMs - a.createdAtMs);
43
+ const count = reviews.length;
44
+ const average = count ? reviews.reduce((sum, review)=>sum + review.rating, 0) / count : 0;
45
+ return {
46
+ reviews,
47
+ aggregate: {
48
+ count,
49
+ average: Math.round(average * 10) / 10
50
+ }
51
+ };
52
+ }
53
+ /**
54
+ * Product reviews (AGL-324). GET returns approved reviews + aggregate;
55
+ * POST submits into the moderation queue, marking `verified` when the
56
+ * email has a paid order containing the product. Pro-plan gated.
57
+ */ export const reviewsHandler = async (req, res)=>{
58
+ var _ref, _ref1;
59
+ var _req_body, _req_body1;
60
+ const isPost = req.method === 'POST';
61
+ const hostId = String((_ref = isPost ? (_req_body = req.body) == null ? void 0 : _req_body.hostId : req.query.hostId) != null ? _ref : '');
62
+ const productId = String((_ref1 = isPost ? (_req_body1 = req.body) == null ? void 0 : _req_body1.productId : req.query.productId) != null ? _ref1 : '');
63
+ if (!hostId || !productId) {
64
+ return res.status(400).json({
65
+ error: 'Missing hostId or productId'
66
+ });
67
+ }
68
+ try {
69
+ const firestore = firebaseAdmin.app().firestore();
70
+ const hostRef = firestore.collection('hosts').doc(hostId);
71
+ if (isPost) {
72
+ var _ref2, _ref3, _ref4, _ref5;
73
+ var _req_body2, _req_body3, _req_body4, _req_body5;
74
+ const org = await getOrgForHost(hostId);
75
+ if (!Aglyn.checkEntitlement(org == null ? void 0 : org.org, 'productReviews')) {
76
+ return res.status(403).json({
77
+ error: 'Reviews are not enabled'
78
+ });
79
+ }
80
+ const rating = Math.min(5, Math.max(1, Math.round(Number((_ref2 = (_req_body2 = req.body) == null ? void 0 : _req_body2.rating) != null ? _ref2 : 0))));
81
+ const body = String((_ref3 = (_req_body3 = req.body) == null ? void 0 : _req_body3.body) != null ? _ref3 : '').trim().slice(0, 2000);
82
+ const authorName = String((_ref4 = (_req_body4 = req.body) == null ? void 0 : _req_body4.authorName) != null ? _ref4 : '').trim().slice(0, 80);
83
+ const authorEmail = String((_ref5 = (_req_body5 = req.body) == null ? void 0 : _req_body5.authorEmail) != null ? _ref5 : '').trim().toLowerCase().slice(0, 120);
84
+ if (!rating || !body || !authorEmail) {
85
+ return res.status(400).json({
86
+ error: 'Rating, review, and email required'
87
+ });
88
+ }
89
+ // Verified buyer: a paid order with the product under this email.
90
+ let verified = false;
91
+ const orders = await hostRef.collection('orders').where('customerEmail', '==', authorEmail).limit(25).get();
92
+ for (const docSnapshot of orders.docs){
93
+ const order = CommerceModel.liftLegacyOrder(docSnapshot.data());
94
+ // Through the shared entitlement test (AGL-2454). "Verified buyer" on a
95
+ // purchase that was refunded line by line is a badge for goods the
96
+ // buyer no longer has — and the inline status literal this replaced
97
+ // only moved on a FULL refund.
98
+ if (CommerceModel.orderEntitlesProduct(order, productId)) {
99
+ verified = true;
100
+ break;
101
+ }
102
+ }
103
+ await hostRef.collection('reviews').add({
104
+ productId,
105
+ rating,
106
+ body,
107
+ authorName: authorName || 'Anonymous',
108
+ authorEmail,
109
+ verified,
110
+ status: 'pending',
111
+ createdAtMs: Date.now()
112
+ });
113
+ return res.status(200).json({
114
+ ok: true,
115
+ pending: true
116
+ });
117
+ }
118
+ const { reviews, aggregate } = await readProductReviews(hostId, productId);
119
+ res.setHeader('Cache-Control', 'public, s-maxage=120, stale-while-revalidate=300');
120
+ return res.status(200).json({
121
+ reviews,
122
+ aggregate
123
+ });
124
+ } catch (error) {
125
+ console.error(error);
126
+ return res.status(500).json({
127
+ error: 'Reviews unavailable'
128
+ });
129
+ }
130
+ };
131
+
132
+ //# sourceMappingURL=reviews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/reviews.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport * as CommerceModel from '../model'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\n\nexport interface PublicProductReview {\n id: string\n rating: number\n body: string\n authorName: string\n verified: boolean\n reply: string | null\n createdAtMs: number\n}\n\nexport interface ProductReviewAggregate {\n count: number\n /** Mean rating, one decimal. */\n average: number\n}\n\n/**\n * Approved reviews for a product, newest first, plus their aggregate.\n *\n * Extracted from the handler (AGL-686) so the site-page resolver can nest\n * `aggregateRating` inside the server-rendered `Product` node. Schema.org\n * wants it as a PROPERTY of the product; the reviews block was emitting a\n * free-standing `AggregateRating` node alongside it, which is orphaned and\n * ignored. One reader means the rating in the structured data and the rating\n * on the page cannot disagree.\n */\nexport async function readProductReviews(\n hostId: string,\n productId: string,\n): Promise<{\n reviews: PublicProductReview[]\n aggregate: ProductReviewAggregate\n}> {\n const hostRef = firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n const reviewsSnapshot = await hostRef\n .collection('reviews')\n .where('productId', '==', productId)\n .where('status', '==', 'approved')\n .limit(100)\n .get()\n const reviews = reviewsSnapshot.docs\n .map((docSnapshot) => ({\n id: docSnapshot.id,\n rating: Number(docSnapshot.get('rating') ?? 0),\n body: String(docSnapshot.get('body') ?? ''),\n authorName: String(docSnapshot.get('authorName') ?? 'Anonymous'),\n verified: Boolean(docSnapshot.get('verified')),\n reply: (docSnapshot.get('reply') as string | undefined) ?? null,\n createdAtMs: Number(docSnapshot.get('createdAtMs') ?? 0),\n }))\n .sort((a, b) => b.createdAtMs - a.createdAtMs)\n const count = reviews.length\n const average = count\n ? reviews.reduce((sum, review) => sum + review.rating, 0) / count\n : 0\n return {\n reviews,\n aggregate: { count, average: Math.round(average * 10) / 10 },\n }\n}\n\n/**\n * Product reviews (AGL-324). GET returns approved reviews + aggregate;\n * POST submits into the moderation queue, marking `verified` when the\n * email has a paid order containing the product. Pro-plan gated.\n */\nexport const reviewsHandler: PluginApiHandler = async (req, res) => {\n const isPost = req.method === 'POST'\n const hostId = String((isPost ? req.body?.hostId : req.query.hostId) ?? '')\n const productId = String(\n (isPost ? req.body?.productId : req.query.productId) ?? '',\n )\n if (!hostId || !productId) {\n return res.status(400).json({ error: 'Missing hostId or productId' })\n }\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n\n if (isPost) {\n const org = await getOrgForHost(hostId)\n if (!Aglyn.checkEntitlement(org?.org as any, 'productReviews')) {\n return res.status(403).json({ error: 'Reviews are not enabled' })\n }\n const rating = Math.min(5, Math.max(1, Math.round(Number(req.body?.rating ?? 0))))\n const body = String(req.body?.body ?? '').trim().slice(0, 2000)\n const authorName = String(req.body?.authorName ?? '').trim().slice(0, 80)\n const authorEmail = String(req.body?.authorEmail ?? '')\n .trim()\n .toLowerCase()\n .slice(0, 120)\n if (!rating || !body || !authorEmail) {\n return res.status(400).json({ error: 'Rating, review, and email required' })\n }\n // Verified buyer: a paid order with the product under this email.\n let verified = false\n const orders = await hostRef\n .collection('orders')\n .where('customerEmail', '==', authorEmail)\n .limit(25)\n .get()\n for (const docSnapshot of orders.docs) {\n const order = CommerceModel.liftLegacyOrder(docSnapshot.data() as any)\n // Through the shared entitlement test (AGL-2454). \"Verified buyer\" on a\n // purchase that was refunded line by line is a badge for goods the\n // buyer no longer has — and the inline status literal this replaced\n // only moved on a FULL refund.\n if (CommerceModel.orderEntitlesProduct(order, productId)) {\n verified = true\n break\n }\n }\n await hostRef.collection('reviews').add({\n productId,\n rating,\n body,\n authorName: authorName || 'Anonymous',\n authorEmail,\n verified,\n status: 'pending',\n createdAtMs: Date.now(),\n })\n return res.status(200).json({ ok: true, pending: true })\n }\n\n const { reviews, aggregate } = await readProductReviews(hostId, productId)\n res.setHeader(\n 'Cache-Control',\n 'public, s-maxage=120, stale-while-revalidate=300',\n )\n return res.status(200).json({ reviews, aggregate })\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Reviews unavailable' })\n }\n}\n"],"names":["Aglyn","CommerceModel","firebaseAdmin","getOrgForHost","readProductReviews","hostId","productId","hostRef","app","firestore","collection","doc","reviewsSnapshot","where","limit","get","reviews","docs","map","docSnapshot","id","rating","Number","body","String","authorName","verified","Boolean","reply","createdAtMs","sort","a","b","count","length","average","reduce","sum","review","aggregate","Math","round","reviewsHandler","req","res","isPost","method","query","status","json","error","org","checkEntitlement","min","max","trim","slice","authorEmail","toLowerCase","orders","order","liftLegacyOrder","data","orderEntitlesProduct","add","Date","now","ok","pending","setHeader","console"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { SitePageEnricher } from '@aglyn/aglyn/server';
18
+ /**
19
+ * Seeds each product grid's FIRST, UNFILTERED page (AGL-659).
20
+ *
21
+ * `/products` shipped 11KB of HTML with zero words in it: the grid fetches
22
+ * its catalog in a `useEffect`, so the server rendered skeleton cards and
23
+ * crawlers indexed an empty shell. The fix is to run the same query on the
24
+ * server and hand the result down through `pageData`.
25
+ *
26
+ * Three things this deliberately does NOT do:
27
+ *
28
+ * - It does not seed anything the visitor can change. Search text, category
29
+ * chips, type chips and the price slider all start empty on mount, so a
30
+ * props-derived query is exactly what the grid's own first fetch would
31
+ * send. Seed a filtered page and SSR would disagree with hydration.
32
+ * - It does not seed later pages. Load more still goes to the API.
33
+ * - It does not share one slice between grids. Seeds are keyed by node id,
34
+ * because a collection-scoped grid and an all-products grid on the same
35
+ * page must not receive each other's items — wrong products would get
36
+ * indexed and visibly swap on hydrate.
37
+ *
38
+ * Failures are swallowed by the enricher runner, and the grid falls back to
39
+ * fetching. A catalog read that errors must not take a page down.
40
+ */
41
+ export declare const commerceSitePageEnricher: SitePageEnricher;
42
+ export default commerceSitePageEnricher;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
+ import { createCatalogReadScope, queryPublicCatalog } from "./catalog.js";
18
+ /** Component id of the block this enricher seeds; persisted, never renamed. */ const PRODUCT_GRID_ID = 'product-grid';
19
+ /**
20
+ * Grids seeded per page. A page with a dozen grids would turn one render
21
+ * into a dozen catalog reads, so the walk stops after this many — the rest
22
+ * fetch client-side exactly as they did before, which is a slower first
23
+ * paint rather than a broken page.
24
+ */ const MAX_SEEDED_GRIDS = 4;
25
+ /**
26
+ * Every product-grid node on the page.
27
+ *
28
+ * `composeScreenNodes` returns `Record<string, node>` — a DENORMALIZED FLAT
29
+ * MAP keyed by node id, whose children are id STRINGS in `nodes`. It does not
30
+ * return a tree, and there is no `children` array anywhere in it.
31
+ *
32
+ * The first version of this walked `children` recursively and therefore
33
+ * matched nothing at all, on any page. It shipped green because the unit
34
+ * tests fed it a nested fixture — the fixture encoded the assumption instead
35
+ * of the actual contract, so the tests only ever proved the walker was
36
+ * self-consistent. Iterating the map's values is both correct and simpler;
37
+ * the flat shape means no recursion is needed.
38
+ *
39
+ * Sorted by id so that the MAX_SEEDED_GRIDS cap takes a deterministic subset
40
+ * rather than whichever ones the map happened to enumerate first.
41
+ */ function collectGridNodes(nodes) {
42
+ if (!nodes || typeof nodes !== 'object') return [];
43
+ const found = [];
44
+ for (const value of Object.values(nodes)){
45
+ if (!value || typeof value !== 'object' || Array.isArray(value)) continue;
46
+ const shaped = value;
47
+ if (shaped.componentId === PRODUCT_GRID_ID && shaped.$id) {
48
+ found.push(shaped);
49
+ }
50
+ }
51
+ return found.sort((a, b)=>String(a.$id).localeCompare(String(b.$id)));
52
+ }
53
+ /** Positive integer from a props value that may arrive as a string. */ function positiveInt(value) {
54
+ const parsed = Number(value);
55
+ if (!Number.isFinite(parsed) || parsed <= 0) return undefined;
56
+ return Math.floor(parsed);
57
+ }
58
+ /**
59
+ * The collection slug a grid on a `/collections/{slug}` page follows when
60
+ * it has no pinned collection — the server-side twin of the grid's
61
+ * `collectionSlugFromLocation()`, which reads `window.location`.
62
+ */ function collectionSlugFromPath(path) {
63
+ const match = path.match(/\/collections\/([^/?#]+)/);
64
+ return match ? decodeURIComponent(match[1]) : '';
65
+ }
66
+ /**
67
+ * Seeds each product grid's FIRST, UNFILTERED page (AGL-659).
68
+ *
69
+ * `/products` shipped 11KB of HTML with zero words in it: the grid fetches
70
+ * its catalog in a `useEffect`, so the server rendered skeleton cards and
71
+ * crawlers indexed an empty shell. The fix is to run the same query on the
72
+ * server and hand the result down through `pageData`.
73
+ *
74
+ * Three things this deliberately does NOT do:
75
+ *
76
+ * - It does not seed anything the visitor can change. Search text, category
77
+ * chips, type chips and the price slider all start empty on mount, so a
78
+ * props-derived query is exactly what the grid's own first fetch would
79
+ * send. Seed a filtered page and SSR would disagree with hydration.
80
+ * - It does not seed later pages. Load more still goes to the API.
81
+ * - It does not share one slice between grids. Seeds are keyed by node id,
82
+ * because a collection-scoped grid and an all-products grid on the same
83
+ * page must not receive each other's items — wrong products would get
84
+ * indexed and visibly swap on hydrate.
85
+ *
86
+ * Failures are swallowed by the enricher runner, and the grid falls back to
87
+ * fetching. A catalog read that errors must not take a page down.
88
+ */ export const commerceSitePageEnricher = async ({ hostId, path, nodes })=>{
89
+ const grids = collectGridNodes(nodes).slice(0, MAX_SEEDED_GRIDS);
90
+ if (!grids.length) return undefined;
91
+ const seeds = {};
92
+ // One scope for this render, so four grids on a page cost one catalog read
93
+ // instead of four identical ones. Each grid still filters and sorts that
94
+ // snapshot for itself — the seeds stay keyed by node id.
95
+ const reads = createCatalogReadScope();
96
+ await Promise.all(grids.map(async (node)=>{
97
+ var _ref, _node_resolvedProps, _props_source;
98
+ const props = (_ref = (_node_resolvedProps = node.resolvedProps) != null ? _node_resolvedProps : node.props) != null ? _ref : {};
99
+ const source = (_props_source = props.source) != null ? _props_source : 'all';
100
+ // Ids first (rename-safe, AGL-343), slugs as the legacy path — the
101
+ // same precedence the grid applies when it builds its own params.
102
+ const collectionSlug = source === 'collection' ? props.collectionSlug || collectionSlugFromPath(path) : props.collectionSlug;
103
+ const pageLimit = positiveInt(props.pageSize);
104
+ const limit = pageLimit != null ? pageLimit : positiveInt(props.maxItems);
105
+ try {
106
+ const result = await queryPublicCatalog(_extends({
107
+ hostId
108
+ }, source === 'collection' ? props.collectionId ? {
109
+ collectionId: props.collectionId
110
+ } : collectionSlug ? {
111
+ collectionSlug
112
+ } : {} : {}, source === 'category' ? props.categoryId ? {
113
+ categoryId: props.categoryId
114
+ } : props.categorySlug ? {
115
+ categorySlug: props.categorySlug
116
+ } : {} : {}, source === 'tag' && props.tag ? {
117
+ tag: props.tag
118
+ } : {}, props.sort ? {
119
+ sort: props.sort
120
+ } : {}, limit ? {
121
+ limit
122
+ } : {}, {
123
+ // Facets ride along only when a control needs them, matching the
124
+ // grid's `facets=1` condition on its first request.
125
+ facets: Boolean(props.showCategories || props.showPriceFilter),
126
+ reads
127
+ }));
128
+ seeds[node.$id] = result;
129
+ } catch (error) {
130
+ // One grid failing leaves the others seeded; this one fetches.
131
+ console.error('commerce grid seed failed', node.$id, error);
132
+ }
133
+ }));
134
+ if (!Object.keys(seeds).length) return undefined;
135
+ return {
136
+ // Merged shallowly into the page props, so this key is the whole
137
+ // `pageData` for a screen page. Screens never reach a page resolver
138
+ // (the loader returns a resolver's answer before enrichers run), so
139
+ // there is no resolver-written pageData here to preserve.
140
+ pageData: {
141
+ commerce: {
142
+ grids: seeds
143
+ }
144
+ }
145
+ };
146
+ };
147
+ export default commerceSitePageEnricher;
148
+
149
+ //# sourceMappingURL=site-page-enricher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/site-page-enricher.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SitePageEnricher } from '@aglyn/aglyn/server'\nimport {\n createCatalogReadScope,\n queryPublicCatalog,\n type PublicCatalogResult,\n} from './catalog'\n\n/** Component id of the block this enricher seeds; persisted, never renamed. */\nconst PRODUCT_GRID_ID = 'product-grid'\n\n/**\n * Grids seeded per page. A page with a dozen grids would turn one render\n * into a dozen catalog reads, so the walk stops after this many — the rest\n * fetch client-side exactly as they did before, which is a slower first\n * paint rather than a broken page.\n */\nconst MAX_SEEDED_GRIDS = 4\n\ninterface GridProps {\n source?: 'all' | 'collection' | 'category' | 'tag'\n collectionId?: string\n collectionSlug?: string\n categoryId?: string\n categorySlug?: string\n tag?: string\n sort?: string\n maxItems?: number | string\n pageSize?: number | string\n showCategories?: boolean\n showPriceFilter?: boolean\n}\n\ninterface ComposedNode {\n $id?: string\n componentId?: string\n props?: Record<string, unknown>\n resolvedProps?: Record<string, unknown>\n /** Child node IDS — denormalized nodes do not nest (see below). */\n nodes?: string[]\n}\n\n/**\n * Every product-grid node on the page.\n *\n * `composeScreenNodes` returns `Record<string, node>` — a DENORMALIZED FLAT\n * MAP keyed by node id, whose children are id STRINGS in `nodes`. It does not\n * return a tree, and there is no `children` array anywhere in it.\n *\n * The first version of this walked `children` recursively and therefore\n * matched nothing at all, on any page. It shipped green because the unit\n * tests fed it a nested fixture — the fixture encoded the assumption instead\n * of the actual contract, so the tests only ever proved the walker was\n * self-consistent. Iterating the map's values is both correct and simpler;\n * the flat shape means no recursion is needed.\n *\n * Sorted by id so that the MAX_SEEDED_GRIDS cap takes a deterministic subset\n * rather than whichever ones the map happened to enumerate first.\n */\nfunction collectGridNodes(nodes: unknown): ComposedNode[] {\n if (!nodes || typeof nodes !== 'object') return []\n const found: ComposedNode[] = []\n for (const value of Object.values(nodes as Record<string, unknown>)) {\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n const shaped = value as ComposedNode\n if (shaped.componentId === PRODUCT_GRID_ID && shaped.$id) {\n found.push(shaped)\n }\n }\n return found.sort((a, b) => String(a.$id).localeCompare(String(b.$id)))\n}\n\n/** Positive integer from a props value that may arrive as a string. */\nfunction positiveInt(value: unknown): number | undefined {\n const parsed = Number(value)\n if (!Number.isFinite(parsed) || parsed <= 0) return undefined\n return Math.floor(parsed)\n}\n\n/**\n * The collection slug a grid on a `/collections/{slug}` page follows when\n * it has no pinned collection — the server-side twin of the grid's\n * `collectionSlugFromLocation()`, which reads `window.location`.\n */\nfunction collectionSlugFromPath(path: string): string {\n const match = path.match(/\\/collections\\/([^/?#]+)/)\n return match ? decodeURIComponent(match[1]) : ''\n}\n\n/**\n * Seeds each product grid's FIRST, UNFILTERED page (AGL-659).\n *\n * `/products` shipped 11KB of HTML with zero words in it: the grid fetches\n * its catalog in a `useEffect`, so the server rendered skeleton cards and\n * crawlers indexed an empty shell. The fix is to run the same query on the\n * server and hand the result down through `pageData`.\n *\n * Three things this deliberately does NOT do:\n *\n * - It does not seed anything the visitor can change. Search text, category\n * chips, type chips and the price slider all start empty on mount, so a\n * props-derived query is exactly what the grid's own first fetch would\n * send. Seed a filtered page and SSR would disagree with hydration.\n * - It does not seed later pages. Load more still goes to the API.\n * - It does not share one slice between grids. Seeds are keyed by node id,\n * because a collection-scoped grid and an all-products grid on the same\n * page must not receive each other's items — wrong products would get\n * indexed and visibly swap on hydrate.\n *\n * Failures are swallowed by the enricher runner, and the grid falls back to\n * fetching. A catalog read that errors must not take a page down.\n */\nexport const commerceSitePageEnricher: SitePageEnricher = async ({\n hostId,\n path,\n nodes,\n}) => {\n const grids = collectGridNodes(nodes).slice(0, MAX_SEEDED_GRIDS)\n if (!grids.length) return undefined\n\n const seeds: Record<string, PublicCatalogResult> = {}\n // One scope for this render, so four grids on a page cost one catalog read\n // instead of four identical ones. Each grid still filters and sorts that\n // snapshot for itself — the seeds stay keyed by node id.\n const reads = createCatalogReadScope()\n await Promise.all(\n grids.map(async (node) => {\n const props = (node.resolvedProps ??\n node.props ??\n {}) as unknown as GridProps\n const source = props.source ?? 'all'\n // Ids first (rename-safe, AGL-343), slugs as the legacy path — the\n // same precedence the grid applies when it builds its own params.\n const collectionSlug =\n source === 'collection'\n ? props.collectionSlug || collectionSlugFromPath(path)\n : props.collectionSlug\n const pageLimit = positiveInt(props.pageSize)\n const limit = pageLimit ?? positiveInt(props.maxItems)\n\n try {\n const result = await queryPublicCatalog({\n hostId,\n ...(source === 'collection'\n ? props.collectionId\n ? { collectionId: props.collectionId }\n : collectionSlug\n ? { collectionSlug }\n : {}\n : {}),\n ...(source === 'category'\n ? props.categoryId\n ? { categoryId: props.categoryId }\n : props.categorySlug\n ? { categorySlug: props.categorySlug }\n : {}\n : {}),\n ...(source === 'tag' && props.tag ? { tag: props.tag } : {}),\n ...(props.sort ? { sort: props.sort } : {}),\n ...(limit ? { limit } : {}),\n // Facets ride along only when a control needs them, matching the\n // grid's `facets=1` condition on its first request.\n facets: Boolean(props.showCategories || props.showPriceFilter),\n reads,\n })\n seeds[node.$id as string] = result\n } catch (error) {\n // One grid failing leaves the others seeded; this one fetches.\n console.error('commerce grid seed failed', node.$id, error)\n }\n }),\n )\n\n if (!Object.keys(seeds).length) return undefined\n\n return {\n // Merged shallowly into the page props, so this key is the whole\n // `pageData` for a screen page. Screens never reach a page resolver\n // (the loader returns a resolver's answer before enrichers run), so\n // there is no resolver-written pageData here to preserve.\n pageData: { commerce: { grids: seeds } },\n }\n}\n\nexport default commerceSitePageEnricher\n"],"names":["createCatalogReadScope","queryPublicCatalog","PRODUCT_GRID_ID","MAX_SEEDED_GRIDS","collectGridNodes","nodes","found","value","Object","values","Array","isArray","shaped","componentId","$id","push","sort","a","b","String","localeCompare","positiveInt","parsed","Number","isFinite","undefined","Math","floor","collectionSlugFromPath","path","match","decodeURIComponent","commerceSitePageEnricher","hostId","grids","slice","length","seeds","reads","Promise","all","map","node","props","resolvedProps","source","collectionSlug","pageLimit","pageSize","limit","maxItems","result","collectionId","categoryId","categorySlug","tag","facets","Boolean","showCategories","showPriceFilter","error","console","keys","pageData","commerce"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { SitePageResolver } from '@aglyn/aglyn/server';
18
+ /**
19
+ * Commerce page resolver (AGL-292/298/418), relocated verbatim from the
20
+ * tenant loader: /products/{slug} renders the host's designated PDP
21
+ * template with product tokens, /collections/{slug} the collection
22
+ * template — both compose server-side and return complete page props.
23
+ * Runs only for paths that didn't match a published screen; returns
24
+ * undefined for everything else so the loader falls through.
25
+ */
26
+ export declare const commerceSitePageResolver: SitePageResolver;
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
+ import { hostCollectionKind } from "@aglyn/aglyn/server";
18
+ import composeScreenNodes from "@aglyn/tenant-runtime/compose-screen-nodes";
19
+ import getScreen from "@aglyn/tenant-runtime/get-screen";
20
+ import { collectSocialImageFacts } from "@aglyn/tenant-runtime/social-image-facts";
21
+ import { firebaseAdmin } from "@aglyn/tenant-data-admin";
22
+ import * as CommerceModel from "../model/index.js";
23
+ import { toPublicProductDetail } from "./product.js";
24
+ import { readProductReviews } from "./reviews.js";
25
+ /**
26
+ * Commerce page resolver (AGL-292/298/418), relocated verbatim from the
27
+ * tenant loader: /products/{slug} renders the host's designated PDP
28
+ * template with product tokens, /collections/{slug} the collection
29
+ * template — both compose server-side and return complete page props.
30
+ * Runs only for paths that didn't match a published screen; returns
31
+ * undefined for everything else so the loader falls through.
32
+ */ export const commerceSitePageResolver = async ({ hostId, host, path })=>{
33
+ const hostRes = {
34
+ host
35
+ };
36
+ // Product detail routes (AGL-292): /products/{slug} renders the
37
+ // host's designated PDP template screen (settings/store
38
+ // `pdpScreenId`, AGL-295) with product tokens; the product-detail
39
+ // block hydrates variants client-side from the same slug. Same
40
+ // mechanism as entry-template screens below.
41
+ const pdpSegments = path.split('/').filter(Boolean);
42
+ if (pdpSegments.length === 2 && pdpSegments[0] === 'products') {
43
+ var _productSnapshot_docs_;
44
+ const adminFirestore = firebaseAdmin.app().firestore();
45
+ const hostDocRef = adminFirestore.collection('hosts').doc(hostId);
46
+ const [storeSettings, productSnapshot] = await Promise.all([
47
+ hostDocRef.collection('settings').doc('store').get(),
48
+ hostDocRef.collection('products').where('slug', '==', pdpSegments[1]).limit(1).get()
49
+ ]);
50
+ const pdpScreenId = storeSettings.get('pdpScreenId');
51
+ const productRaw = (_productSnapshot_docs_ = productSnapshot.docs[0]) == null ? void 0 : _productSnapshot_docs_.data();
52
+ if (pdpScreenId && productRaw && !productRaw.deletedAt && productRaw.status === 'active') {
53
+ const product = CommerceModel.liftLegacyProduct(productRaw);
54
+ const templateRes = await getScreen({
55
+ hostId,
56
+ screenId: pdpScreenId,
57
+ // A PDP template renders against a routed PRODUCT, never at an address
58
+ // of its own, so it is served here and 404s everywhere else (AGL-1400).
59
+ allowTemplate: true
60
+ });
61
+ if (templateRes.screen) {
62
+ var _product_description, _ref, _ref1;
63
+ var _templateRes_screen_seo, _hostRes_host_seo, _hostRes_host, _product_mediaUrls;
64
+ const [minPrice, maxPrice] = CommerceModel.productPriceRange(product);
65
+ // Best-effort: a reviews read that fails costs the page its rating
66
+ // snippet, not the page.
67
+ const productReviews = await readProductReviews(hostId, productSnapshot.docs[0].id).catch((error)=>{
68
+ console.error('product review aggregate failed', error);
69
+ return {
70
+ reviews: [],
71
+ aggregate: {
72
+ count: 0,
73
+ average: 0
74
+ }
75
+ };
76
+ });
77
+ // The head shares this page as the template's image, then the site
78
+ // default, so their documents are read in the template's own batch
79
+ // (AGL-2850).
80
+ const card = collectSocialImageFacts([
81
+ (_templateRes_screen_seo = templateRes.screen.seo) == null ? void 0 : _templateRes_screen_seo.image,
82
+ (_hostRes_host = hostRes.host) == null ? void 0 : (_hostRes_host_seo = _hostRes_host.seo) == null ? void 0 : _hostRes_host_seo.image
83
+ ]);
84
+ const templateNodes = await composeScreenNodes({
85
+ hostId,
86
+ screenId: pdpScreenId,
87
+ screen: templateRes.screen,
88
+ socialImages: card.socialImages,
89
+ // The template's host variables, and its layout's, fill in from
90
+ // this site as they do on every other page (AGL-2883).
91
+ host: hostRes.host,
92
+ tokens: {
93
+ 'product.name': product.name,
94
+ 'product.description': (_product_description = product.description) != null ? _product_description : '',
95
+ 'product.price': minPrice === maxPrice ? `$${minPrice}` : `From $${minPrice}`,
96
+ 'product.image': (_ref = (_ref1 = (_product_mediaUrls = product.mediaUrls) == null ? void 0 : _product_mediaUrls[0]) != null ? _ref1 : product.imageUrl) != null ? _ref : '',
97
+ 'product.slug': product.slug
98
+ }
99
+ });
100
+ if (templateNodes) {
101
+ var _templateRes_screen_seo1, _ref2, _ref3, _ref4;
102
+ var _product_seo, _product_seo1;
103
+ return {
104
+ props: JSON.parse(JSON.stringify(_extends({
105
+ // The PDP block used to fetch this in an effect, so the
106
+ // server rendered a skeleton and crawlers saw a product page
107
+ // with no product in it (AGL-659). The product is already
108
+ // loaded here — hand it down so it renders server-side.
109
+ pageData: {
110
+ commerce: _extends({
111
+ product: toPublicProductDetail(productSnapshot.docs[0].id, product)
112
+ }, productReviews.aggregate.count ? {
113
+ reviews: productReviews
114
+ } : {})
115
+ },
116
+ data: {
117
+ host: hostRes.host,
118
+ screen: {
119
+ data: _extends({}, templateRes.screen, {
120
+ // The product NAMES this page; the template's own name
121
+ // ("Product detail") describes none of the products it
122
+ // renders. Kept distinct from the SEO title because the
123
+ // head treats an authored title as verbatim and a name
124
+ // as the side the site title joins (AGL-1341) — so a
125
+ // product with its own SEO title gets exactly that, and
126
+ // one without gets "Blue Widget – Acme Store".
127
+ displayName: product.name,
128
+ seo: _extends({}, (_templateRes_screen_seo1 = templateRes.screen.seo) != null ? _templateRes_screen_seo1 : {}, {
129
+ // Only when the PRODUCT authored one: inheriting the
130
+ // template screen's title would give every product
131
+ // page in the store the same `<title>`.
132
+ title: (_ref2 = (_product_seo = product.seo) == null ? void 0 : _product_seo.title) != null ? _ref2 : undefined,
133
+ description: (_ref3 = (_ref4 = (_product_seo1 = product.seo) == null ? void 0 : _product_seo1.description) != null ? _ref4 : product.description) != null ? _ref3 : undefined
134
+ })
135
+ })
136
+ }
137
+ },
138
+ nodes: templateNodes
139
+ }, card.collected()))),
140
+ revalidate: 60
141
+ };
142
+ }
143
+ }
144
+ }
145
+ }
146
+ // Commerce collection routes (AGL-298): /collections/{slug} renders
147
+ // the designated collection template with collection tokens; the
148
+ // product-grid block derives the same slug from the URL.
149
+ if (pdpSegments.length === 2 && pdpSegments[0] === 'collections') {
150
+ var _collectionSnapshot_docs_find;
151
+ const adminFirestore = firebaseAdmin.app().firestore();
152
+ const hostDocRef = adminFirestore.collection('hosts').doc(hostId);
153
+ const [storeSettings, collectionSnapshot] = await Promise.all([
154
+ hostDocRef.collection('settings').doc('store').get(),
155
+ hostDocRef.collection('collections').where('slug', '==', pdpSegments[1]).limit(5).get()
156
+ ]);
157
+ const collectionScreenId = storeSettings.get('collectionScreenId');
158
+ // Content collections share this path and a slug is only unique within a
159
+ // kind (AGL-954), so take the first CATALOG match rather than the first
160
+ // doc — otherwise a blog with the same slug renders as a product page.
161
+ const shopCollection = (_collectionSnapshot_docs_find = collectionSnapshot.docs.find((docSnapshot)=>hostCollectionKind(docSnapshot.data()) === 'catalog')) == null ? void 0 : _collectionSnapshot_docs_find.data();
162
+ if (collectionScreenId && shopCollection) {
163
+ const templateRes = await getScreen({
164
+ hostId,
165
+ screenId: collectionScreenId,
166
+ allowTemplate: true
167
+ });
168
+ if (templateRes.screen) {
169
+ var _shopCollection_description, _shopCollection_imageUrl;
170
+ var _templateRes_screen_seo2, _hostRes_host_seo1, _hostRes_host1;
171
+ // As on the PDP above: the template's image, then the site default
172
+ // (AGL-2850).
173
+ const card = collectSocialImageFacts([
174
+ (_templateRes_screen_seo2 = templateRes.screen.seo) == null ? void 0 : _templateRes_screen_seo2.image,
175
+ (_hostRes_host1 = hostRes.host) == null ? void 0 : (_hostRes_host_seo1 = _hostRes_host1.seo) == null ? void 0 : _hostRes_host_seo1.image
176
+ ]);
177
+ const templateNodes = await composeScreenNodes({
178
+ hostId,
179
+ screenId: collectionScreenId,
180
+ screen: templateRes.screen,
181
+ socialImages: card.socialImages,
182
+ // As on the PDP above (AGL-2883).
183
+ host: hostRes.host,
184
+ tokens: {
185
+ 'collection.name': shopCollection.name,
186
+ 'collection.description': (_shopCollection_description = shopCollection.description) != null ? _shopCollection_description : '',
187
+ 'collection.image': (_shopCollection_imageUrl = shopCollection.imageUrl) != null ? _shopCollection_imageUrl : '',
188
+ 'collection.slug': shopCollection.slug
189
+ }
190
+ });
191
+ if (templateNodes) {
192
+ var _templateRes_screen_seo3, _shopCollection_description1;
193
+ return {
194
+ props: JSON.parse(JSON.stringify(_extends({
195
+ data: {
196
+ host: hostRes.host,
197
+ screen: {
198
+ data: _extends({}, templateRes.screen, {
199
+ // As on the PDP above: the catalog collection names the
200
+ // page, and a name takes the site title after it while
201
+ // an authored SEO title would not (AGL-1341). A shop
202
+ // collection has no SEO title field of its own, so the
203
+ // template's must not stand in for one.
204
+ displayName: shopCollection.name,
205
+ seo: _extends({}, (_templateRes_screen_seo3 = templateRes.screen.seo) != null ? _templateRes_screen_seo3 : {}, {
206
+ title: undefined,
207
+ description: (_shopCollection_description1 = shopCollection.description) != null ? _shopCollection_description1 : undefined
208
+ })
209
+ })
210
+ }
211
+ },
212
+ nodes: templateNodes
213
+ }, card.collected()))),
214
+ revalidate: 60
215
+ };
216
+ }
217
+ }
218
+ }
219
+ }
220
+ return undefined;
221
+ };
222
+
223
+ //# sourceMappingURL=site-page-resolver.js.map