@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,91 @@
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 { firebaseAdmin } from "@aglyn/tenant-data-admin";
17
+ import { requireActiveMember } from "./membership.js";
18
+ /**
19
+ * Subscriber self-service (AGL-303): opens the Stripe Billing Portal for
20
+ * the signed-in member's storefront subscription (cancel, switch
21
+ * payment method). Member-gated; the portal customer is matched by the
22
+ * member's email through the recorded subscription doc.
23
+ */ export const subscriptionPortalHandler = async (req, res)=>{
24
+ var _ref;
25
+ var _req_body;
26
+ if (req.method !== 'POST') {
27
+ return res.status(405).json({
28
+ error: 'Method not allowed'
29
+ });
30
+ }
31
+ if (!process.env.STRIPE_SECRET_KEY) {
32
+ return res.status(501).json({
33
+ error: 'Billing is not configured.'
34
+ });
35
+ }
36
+ const hostId = String((_ref = (_req_body = req.body) == null ? void 0 : _req_body.hostId) != null ? _ref : '');
37
+ if (!hostId) return res.status(400).json({
38
+ error: 'Missing hostId'
39
+ });
40
+ try {
41
+ var _auth_member_get, _req_headers_referer;
42
+ var _subscriptions_docs_;
43
+ // Suspension gate (AGL-550): suspended members (AGL-546) cannot
44
+ // open the billing portal — 403'd with the session cookie cleared.
45
+ const auth = await requireActiveMember(req, res, hostId);
46
+ if (!auth) return;
47
+ const firestore = firebaseAdmin.app().firestore();
48
+ const hostRef = firestore.collection('hosts').doc(hostId);
49
+ const email = String((_auth_member_get = auth.member.get('email')) != null ? _auth_member_get : '');
50
+ if (!email) return res.status(401).json({
51
+ error: 'Not signed in'
52
+ });
53
+ const subscriptions = await hostRef.collection('subscriptions').where('customerEmail', '==', email).limit(1).get();
54
+ const customerId = (_subscriptions_docs_ = subscriptions.docs[0]) == null ? void 0 : _subscriptions_docs_.get('stripeCustomerId');
55
+ if (!customerId) {
56
+ return res.status(404).json({
57
+ error: 'No subscription found'
58
+ });
59
+ }
60
+ const referer = String((_req_headers_referer = req.headers.referer) != null ? _req_headers_referer : '');
61
+ const origin = `https://${req.headers.host}`;
62
+ const response = await fetch('https://api.stripe.com/v1/billing_portal/sessions', {
63
+ method: 'POST',
64
+ headers: {
65
+ Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,
66
+ 'Content-Type': 'application/x-www-form-urlencoded'
67
+ },
68
+ body: new URLSearchParams({
69
+ customer: String(customerId),
70
+ return_url: referer.startsWith('http') ? referer : origin
71
+ }).toString()
72
+ });
73
+ const session = await response.json();
74
+ if (!response.ok || !session.url) {
75
+ console.error('Portal error', session == null ? void 0 : session.error);
76
+ return res.status(502).json({
77
+ error: 'Portal unavailable'
78
+ });
79
+ }
80
+ return res.status(200).json({
81
+ url: session.url
82
+ });
83
+ } catch (error) {
84
+ console.error(error);
85
+ return res.status(500).json({
86
+ error: 'Portal unavailable'
87
+ });
88
+ }
89
+ };
90
+
91
+ //# sourceMappingURL=subscription-portal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/subscription-portal.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 { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { requireActiveMember } from './membership'\n\n/**\n * Subscriber self-service (AGL-303): opens the Stripe Billing Portal for\n * the signed-in member's storefront subscription (cancel, switch\n * payment method). Member-gated; the portal customer is matched by the\n * member's email through the recorded subscription doc.\n */\nexport const subscriptionPortalHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n if (!process.env.STRIPE_SECRET_KEY) {\n return res.status(501).json({ error: 'Billing is not configured.' })\n }\n const hostId = String(req.body?.hostId ?? '')\n if (!hostId) return res.status(400).json({ error: 'Missing hostId' })\n\n try {\n // Suspension gate (AGL-550): suspended members (AGL-546) cannot\n // open the billing portal — 403'd with the session cookie cleared.\n const auth = await requireActiveMember(req, res, hostId)\n if (!auth) return\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const email = String(auth.member.get('email') ?? '')\n if (!email) return res.status(401).json({ error: 'Not signed in' })\n const subscriptions = await hostRef\n .collection('subscriptions')\n .where('customerEmail', '==', email)\n .limit(1)\n .get()\n const customerId = subscriptions.docs[0]?.get('stripeCustomerId')\n if (!customerId) {\n return res.status(404).json({ error: 'No subscription found' })\n }\n const referer = String(req.headers.referer ?? '')\n const origin = `https://${req.headers.host}`\n const response = await fetch(\n 'https://api.stripe.com/v1/billing_portal/sessions',\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n customer: String(customerId),\n return_url: referer.startsWith('http') ? referer : origin,\n }).toString(),\n },\n )\n const session = await response.json()\n if (!response.ok || !session.url) {\n console.error('Portal error', session?.error)\n return res.status(502).json({ error: 'Portal unavailable' })\n }\n return res.status(200).json({ url: session.url })\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Portal unavailable' })\n }\n}\n"],"names":["firebaseAdmin","requireActiveMember","subscriptionPortalHandler","req","res","method","status","json","error","process","env","STRIPE_SECRET_KEY","hostId","String","body","auth","subscriptions","firestore","app","hostRef","collection","doc","email","member","get","where","limit","customerId","docs","referer","headers","origin","host","response","fetch","Authorization","URLSearchParams","customer","return_url","startsWith","toString","session","ok","url","console"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,aAAa,QAAQ,2BAA0B;AACxD,SAASC,mBAAmB,QAAQ,kBAAc;AAElD;;;;;CAKC,GACD,OAAO,MAAMC,4BAA8C,OAAOC,KAAKC;;QAO/CD;IANtB,IAAIA,IAAIE,MAAM,KAAK,QAAQ;QACzB,OAAOD,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAqB;IAC5D;IACA,IAAI,CAACC,QAAQC,GAAG,CAACC,iBAAiB,EAAE;QAClC,OAAOP,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAA6B;IACpE;IACA,MAAMI,SAASC,gBAAOV,YAAAA,IAAIW,IAAI,qBAARX,UAAUS,MAAM,mBAAI;IAC1C,IAAI,CAACA,QAAQ,OAAOR,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;QAAEC,OAAO;IAAiB;IAEnE,IAAI;YAOmBO,kBAWEZ;YAJJa;QAbnB,gEAAgE;QAChE,mEAAmE;QACnE,MAAMD,OAAO,MAAMd,oBAAoBE,KAAKC,KAAKQ;QACjD,IAAI,CAACG,MAAM;QACX,MAAME,YAAYjB,cAAckB,GAAG,GAAGD,SAAS;QAC/C,MAAME,UAAUF,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACT;QAClD,MAAMU,QAAQT,QAAOE,mBAAAA,KAAKQ,MAAM,CAACC,GAAG,CAAC,oBAAhBT,mBAA4B;QACjD,IAAI,CAACO,OAAO,OAAOlB,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAgB;QACjE,MAAMQ,gBAAgB,MAAMG,QACzBC,UAAU,CAAC,iBACXK,KAAK,CAAC,iBAAiB,MAAMH,OAC7BI,KAAK,CAAC,GACNF,GAAG;QACN,MAAMG,cAAaX,uBAAAA,cAAcY,IAAI,CAAC,EAAE,qBAArBZ,qBAAuBQ,GAAG,CAAC;QAC9C,IAAI,CAACG,YAAY;YACf,OAAOvB,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;gBAAEC,OAAO;YAAwB;QAC/D;QACA,MAAMqB,UAAUhB,QAAOV,uBAAAA,IAAI2B,OAAO,CAACD,OAAO,YAAnB1B,uBAAuB;QAC9C,MAAM4B,SAAS,CAAC,QAAQ,EAAE5B,IAAI2B,OAAO,CAACE,IAAI,EAAE;QAC5C,MAAMC,WAAW,MAAMC,MACrB,qDACA;YACE7B,QAAQ;YACRyB,SAAS;gBACPK,eAAe,CAAC,OAAO,EAAE1B,QAAQC,GAAG,CAACC,iBAAiB,EAAE;gBACxD,gBAAgB;YAClB;YACAG,MAAM,IAAIsB,gBAAgB;gBACxBC,UAAUxB,OAAOc;gBACjBW,YAAYT,QAAQU,UAAU,CAAC,UAAUV,UAAUE;YACrD,GAAGS,QAAQ;QACb;QAEF,MAAMC,UAAU,MAAMR,SAAS1B,IAAI;QACnC,IAAI,CAAC0B,SAASS,EAAE,IAAI,CAACD,QAAQE,GAAG,EAAE;YAChCC,QAAQpC,KAAK,CAAC,gBAAgBiC,2BAAAA,QAASjC,KAAK;YAC5C,OAAOJ,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;gBAAEC,OAAO;YAAqB;QAC5D;QACA,OAAOJ,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEoC,KAAKF,QAAQE,GAAG;QAAC;IACjD,EAAE,OAAOnC,OAAO;QACdoC,QAAQpC,KAAK,CAACA;QACd,OAAOJ,IAAIE,MAAM,CAAC,KAAKC,IAAI,CAAC;YAAEC,OAAO;QAAqB;IAC5D;AACF,EAAC"}
@@ -0,0 +1,190 @@
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 PluginJobHostGate } from '@aglyn/aglyn/server';
18
+ /**
19
+ * The durable outbox for the dropship supplier notification (AGL-2473).
20
+ *
21
+ * ## What was wrong
22
+ *
23
+ * `billing-webhook.ts` routed a paid dropship order inside
24
+ * `void (async () => { … })()`, and the last thing that block did was
25
+ * `await fetch(supplier.webhookUrl, …)` — an endpoint the MERCHANT typed into
26
+ * a console field, on a host Aglyn neither runs nor monitors. Vercel freezes
27
+ * the container the instant the response is written, so a supplier that is
28
+ * slow, rate-limiting, or simply down is a supplier that is never told. The
29
+ * order is paid, the buyer is thanked, the merchant sees "Sent to supplier X"
30
+ * on the timeline, and NOTHING ANYWHERE records that the POST is still owed —
31
+ * so no later pass can find it and no report can list it. It surfaces when the
32
+ * customer asks where their parcel is.
33
+ *
34
+ * ## Why not just `await` it
35
+ *
36
+ * AGL-2161 fixed the other four fire-and-forget sites in that file and
37
+ * deliberately left this one, because awaiting it is worse rather than better:
38
+ * a supplier taking 30s pushes the handler past Stripe's delivery window,
39
+ * Stripe redelivers, and the redelivery re-enters a fan-out whose only
40
+ * idempotency is one `created` flag upstream. A silently dropped notification
41
+ * would have been traded for a DUPLICATED order. `refund.ts` awaits its own
42
+ * sibling and says so in a comment — correctly, because that sibling only
43
+ * touches our own Firestore.
44
+ *
45
+ * So the line this module draws is not "fast vs slow" but **ours vs theirs**.
46
+ * Everything the routing block does to Aglyn's own storage — the callback
47
+ * token, the timeline entry, the supplier email through our own provider — is
48
+ * now AWAITED on the response path, exactly like `refund.ts`. The one call to a
49
+ * stranger's server becomes a row here, and the response no longer waits on it.
50
+ *
51
+ * ## The mechanism
52
+ *
53
+ * A Firestore-backed outbox drained by the plugin-job beat that already runs
54
+ * the two commerce recovery passes (`server.ts`). No new infrastructure: the
55
+ * beat is a Cloud Scheduler function POSTing the tenant runner route, and it
56
+ * has carried bounded scans since AGL-2227.
57
+ *
58
+ * * **Idempotent enqueue.** The id is `{hostId}__{orderId}__{supplierId}` and
59
+ * the write is `create()`, which REFUSES an existing document, so a
60
+ * redelivery cannot reset a retry part-way through its backoff. The AGL-498
61
+ * existence guard upstream already returns before this fan-out, but
62
+ * `reconcile-stock.ts` documents at length why one flag over a dozen effects
63
+ * is not something to lean on.
64
+ * * **Backoff.** 1m, 5m, 15m, 1h, 6h — about seven and a half hours of cover,
65
+ * which is a supplier's overnight deploy but not their week off.
66
+ * * **Dead letter.** After {@link SUPPLIER_DELIVERY_MAX_ATTEMPTS} the row is
67
+ * left as `failed`, the ORDER's own timeline is stamped, and host managers
68
+ * get a notification. The merchant reading the order they were paid for can
69
+ * see that it never reached the supplier — the thing the old code could not
70
+ * tell anyone, because it wrote nothing down.
71
+ *
72
+ * ## Two placement decisions, both deliberate
73
+ *
74
+ * **TOP-LEVEL, not `hosts/{hostId}/supplierDeliveries`.** The host catch-all in
75
+ * the rules file is PERMISSIVE by default — a subcollection nobody names in its
76
+ * three exclusion lists is one every site editor can write from the browser —
77
+ * and the row carries the exact JSON body we sign and POST, so an editor-
78
+ * writable row is an editor-chosen payload delivered under the supplier's own
79
+ * shared secret. A top-level collection matches no rule in
80
+ * `cloud/firebase-firestore.rules` at all and is therefore denied to every
81
+ * client by default, the same footing as `platform/pluginJobs`. It also keeps
82
+ * the drain on an ordinary collection query: a collection-GROUP `where` would
83
+ * need a `COLLECTION_GROUP_ASC` fieldOverride, and AGL-1793 is the record of
84
+ * both commerce crons being silently dead in production for want of exactly
85
+ * that. Neither a rules deploy nor an index deploy is owed for this change.
86
+ *
87
+ * **A delivered row is DELETED, not stamped `delivered`.** The body holds the
88
+ * buyer's email and name, and a top-level document is outside the
89
+ * `hosts/{hostId}` recursive delete an erasure request runs. Retaining the
90
+ * happy path would accumulate third-party PII in a place erasure does not
91
+ * reach, to record something the order's own `routed` timeline entry already
92
+ * says. Dead-lettered rows survive, because those are the ones a human has to
93
+ * act on and the merchant has been told about them.
94
+ */
95
+ /** Top-level collection. Matches no rule, so no client may read or write it. */
96
+ export declare const SUPPLIER_DELIVERY_COLLECTION = "supplierDeliveries";
97
+ /** Attempts before a delivery is dead-lettered. */
98
+ export declare const SUPPLIER_DELIVERY_MAX_ATTEMPTS = 6;
99
+ /**
100
+ * Delay before the next retry, indexed by attempts ALREADY made.
101
+ *
102
+ * The first entry is 60s and the job beat is also 60s, so a supplier that
103
+ * blipped is retried on the next tick rather than a quarter of an hour later —
104
+ * the difference between a parcel that ships today and one that does not.
105
+ */
106
+ export declare const SUPPLIER_DELIVERY_BACKOFF_MS: readonly number[];
107
+ /**
108
+ * Per-attempt timeout. Nothing user-facing waits on this — it exists so one
109
+ * hung supplier cannot hold the shared job beat open for the whole scan.
110
+ */
111
+ export declare const SUPPLIER_DELIVERY_TIMEOUT_MS = 10000;
112
+ /** Rows examined per drain. Bounded like every other scan on the beat. */
113
+ export declare const SUPPLIER_DELIVERY_SCAN_LIMIT = 100;
114
+ export type SupplierDeliveryStatus = 'pending' | 'failed';
115
+ export interface SupplierDeliveryRecord {
116
+ status: SupplierDeliveryStatus;
117
+ hostId: string;
118
+ orderId: string;
119
+ supplierId: string;
120
+ supplierName: string;
121
+ /** The endpoint as configured when the order was routed, for the record. */
122
+ url: string;
123
+ /** The exact JSON the supplier is sent; signed at delivery time. */
124
+ body: string;
125
+ attempts: number;
126
+ nextAttemptAtMs: number;
127
+ createdAtMs: number;
128
+ lastError?: string;
129
+ lastStatus?: number;
130
+ failedAtMs?: number;
131
+ }
132
+ export interface SupplierDeliveryScanResult {
133
+ scanned: number;
134
+ delivered: number;
135
+ retried: number;
136
+ deadLettered: number;
137
+ /** Retired without delivery because the merchant removed the endpoint. */
138
+ cancelled: number;
139
+ /** Left pending, with the retry budget intact, because the site is locked. */
140
+ skippedLocked: number;
141
+ }
142
+ /**
143
+ * The delay owed after `attempts` failures, clamped to the last step.
144
+ *
145
+ * Clamped rather than extrapolated: the tail entry is already six hours, and a
146
+ * dead letter is what comes after it, not a longer and longer silence.
147
+ */
148
+ export declare function supplierDeliveryBackoffMs(attempts: number): number;
149
+ /**
150
+ * The outbox document id for one host/order/supplier triple.
151
+ *
152
+ * Deterministic, so `create()` is the idempotency. `__` rather than `:` or `/`:
153
+ * a slash would make `.doc()` build a PATH instead of an id (AGL-1771), and the
154
+ * separator has to survive a Stripe session id, which already contains `_`.
155
+ * Firestore reserves ids fully matching `__.*__`; this never is, because all
156
+ * three parts are non-empty and the id neither starts nor ends with `__`.
157
+ */
158
+ export declare function supplierDeliveryId(hostId: string, orderId: string, supplierId: string): string;
159
+ /**
160
+ * Records that a supplier POST is owed. One Firestore write, awaited.
161
+ *
162
+ * Returns `'queued'`, `'exists'` when a row for this triple is already in
163
+ * flight, or `'skipped'`. NEVER THROWS: the caller is a paid order's fulfilment
164
+ * path, and a queue that cannot be written must not take the receipt down with
165
+ * it. The refusal is logged, which is strictly more than the old code managed
166
+ * on the same failure.
167
+ */
168
+ export declare function enqueueSupplierDelivery(options: {
169
+ firestore: FirebaseFirestore.Firestore;
170
+ hostId: string;
171
+ orderId: string;
172
+ supplierId: string;
173
+ supplierName: string;
174
+ url: string;
175
+ body: string;
176
+ now?: number;
177
+ }): Promise<'queued' | 'exists' | 'skipped'>;
178
+ /**
179
+ * Drains the supplier outbox. Bounded, and safe to run twice.
180
+ *
181
+ * `nextAttemptAtMs` is filtered IN MEMORY rather than added to the query, which
182
+ * would need a composite index for one field's worth of selectivity. The cost
183
+ * is that a row still inside its backoff occupies one of the
184
+ * {@link SUPPLIER_DELIVERY_SCAN_LIMIT} slots; with at most
185
+ * {@link SUPPLIER_DELIVERY_MAX_ATTEMPTS} attempts per row the queue always
186
+ * drains rather than growing a permanent head.
187
+ */
188
+ export declare function scanSupplierDeliveries(
189
+ /** The lockdown gate, injected by the caller (AGL-2495). Not optional. */
190
+ gate: PluginJobHostGate, now?: number): Promise<SupplierDeliveryScanResult>;
@@ -0,0 +1,342 @@
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 { firebaseAdmin, notifyHostManagers } from "@aglyn/tenant-data-admin";
18
+ import { isDocumentId } from "@aglyn/tenant-data-admin/server/document-id";
19
+ import { createHmac } from "crypto";
20
+ /**
21
+ * The durable outbox for the dropship supplier notification (AGL-2473).
22
+ *
23
+ * ## What was wrong
24
+ *
25
+ * `billing-webhook.ts` routed a paid dropship order inside
26
+ * `void (async () => { … })()`, and the last thing that block did was
27
+ * `await fetch(supplier.webhookUrl, …)` — an endpoint the MERCHANT typed into
28
+ * a console field, on a host Aglyn neither runs nor monitors. Vercel freezes
29
+ * the container the instant the response is written, so a supplier that is
30
+ * slow, rate-limiting, or simply down is a supplier that is never told. The
31
+ * order is paid, the buyer is thanked, the merchant sees "Sent to supplier X"
32
+ * on the timeline, and NOTHING ANYWHERE records that the POST is still owed —
33
+ * so no later pass can find it and no report can list it. It surfaces when the
34
+ * customer asks where their parcel is.
35
+ *
36
+ * ## Why not just `await` it
37
+ *
38
+ * AGL-2161 fixed the other four fire-and-forget sites in that file and
39
+ * deliberately left this one, because awaiting it is worse rather than better:
40
+ * a supplier taking 30s pushes the handler past Stripe's delivery window,
41
+ * Stripe redelivers, and the redelivery re-enters a fan-out whose only
42
+ * idempotency is one `created` flag upstream. A silently dropped notification
43
+ * would have been traded for a DUPLICATED order. `refund.ts` awaits its own
44
+ * sibling and says so in a comment — correctly, because that sibling only
45
+ * touches our own Firestore.
46
+ *
47
+ * So the line this module draws is not "fast vs slow" but **ours vs theirs**.
48
+ * Everything the routing block does to Aglyn's own storage — the callback
49
+ * token, the timeline entry, the supplier email through our own provider — is
50
+ * now AWAITED on the response path, exactly like `refund.ts`. The one call to a
51
+ * stranger's server becomes a row here, and the response no longer waits on it.
52
+ *
53
+ * ## The mechanism
54
+ *
55
+ * A Firestore-backed outbox drained by the plugin-job beat that already runs
56
+ * the two commerce recovery passes (`server.ts`). No new infrastructure: the
57
+ * beat is a Cloud Scheduler function POSTing the tenant runner route, and it
58
+ * has carried bounded scans since AGL-2227.
59
+ *
60
+ * * **Idempotent enqueue.** The id is `{hostId}__{orderId}__{supplierId}` and
61
+ * the write is `create()`, which REFUSES an existing document, so a
62
+ * redelivery cannot reset a retry part-way through its backoff. The AGL-498
63
+ * existence guard upstream already returns before this fan-out, but
64
+ * `reconcile-stock.ts` documents at length why one flag over a dozen effects
65
+ * is not something to lean on.
66
+ * * **Backoff.** 1m, 5m, 15m, 1h, 6h — about seven and a half hours of cover,
67
+ * which is a supplier's overnight deploy but not their week off.
68
+ * * **Dead letter.** After {@link SUPPLIER_DELIVERY_MAX_ATTEMPTS} the row is
69
+ * left as `failed`, the ORDER's own timeline is stamped, and host managers
70
+ * get a notification. The merchant reading the order they were paid for can
71
+ * see that it never reached the supplier — the thing the old code could not
72
+ * tell anyone, because it wrote nothing down.
73
+ *
74
+ * ## Two placement decisions, both deliberate
75
+ *
76
+ * **TOP-LEVEL, not `hosts/{hostId}/supplierDeliveries`.** The host catch-all in
77
+ * the rules file is PERMISSIVE by default — a subcollection nobody names in its
78
+ * three exclusion lists is one every site editor can write from the browser —
79
+ * and the row carries the exact JSON body we sign and POST, so an editor-
80
+ * writable row is an editor-chosen payload delivered under the supplier's own
81
+ * shared secret. A top-level collection matches no rule in
82
+ * `cloud/firebase-firestore.rules` at all and is therefore denied to every
83
+ * client by default, the same footing as `platform/pluginJobs`. It also keeps
84
+ * the drain on an ordinary collection query: a collection-GROUP `where` would
85
+ * need a `COLLECTION_GROUP_ASC` fieldOverride, and AGL-1793 is the record of
86
+ * both commerce crons being silently dead in production for want of exactly
87
+ * that. Neither a rules deploy nor an index deploy is owed for this change.
88
+ *
89
+ * **A delivered row is DELETED, not stamped `delivered`.** The body holds the
90
+ * buyer's email and name, and a top-level document is outside the
91
+ * `hosts/{hostId}` recursive delete an erasure request runs. Retaining the
92
+ * happy path would accumulate third-party PII in a place erasure does not
93
+ * reach, to record something the order's own `routed` timeline entry already
94
+ * says. Dead-lettered rows survive, because those are the ones a human has to
95
+ * act on and the merchant has been told about them.
96
+ */ /** Top-level collection. Matches no rule, so no client may read or write it. */ export const SUPPLIER_DELIVERY_COLLECTION = 'supplierDeliveries';
97
+ /** Attempts before a delivery is dead-lettered. */ export const SUPPLIER_DELIVERY_MAX_ATTEMPTS = 6;
98
+ /**
99
+ * Delay before the next retry, indexed by attempts ALREADY made.
100
+ *
101
+ * The first entry is 60s and the job beat is also 60s, so a supplier that
102
+ * blipped is retried on the next tick rather than a quarter of an hour later —
103
+ * the difference between a parcel that ships today and one that does not.
104
+ */ export const SUPPLIER_DELIVERY_BACKOFF_MS = [
105
+ 60000,
106
+ 300000,
107
+ 900000,
108
+ 3600000,
109
+ 21600000
110
+ ];
111
+ /**
112
+ * Per-attempt timeout. Nothing user-facing waits on this — it exists so one
113
+ * hung supplier cannot hold the shared job beat open for the whole scan.
114
+ */ export const SUPPLIER_DELIVERY_TIMEOUT_MS = 10000;
115
+ /** Rows examined per drain. Bounded like every other scan on the beat. */ export const SUPPLIER_DELIVERY_SCAN_LIMIT = 100;
116
+ /** gRPC `Status.ALREADY_EXISTS` — what `create()` on a live path carries. */ const GRPC_ALREADY_EXISTS = 6;
117
+ /**
118
+ * The delay owed after `attempts` failures, clamped to the last step.
119
+ *
120
+ * Clamped rather than extrapolated: the tail entry is already six hours, and a
121
+ * dead letter is what comes after it, not a longer and longer silence.
122
+ */ export function supplierDeliveryBackoffMs(attempts) {
123
+ const last = SUPPLIER_DELIVERY_BACKOFF_MS.length - 1;
124
+ return SUPPLIER_DELIVERY_BACKOFF_MS[Math.max(0, Math.min(attempts - 1, last))];
125
+ }
126
+ /**
127
+ * The outbox document id for one host/order/supplier triple.
128
+ *
129
+ * Deterministic, so `create()` is the idempotency. `__` rather than `:` or `/`:
130
+ * a slash would make `.doc()` build a PATH instead of an id (AGL-1771), and the
131
+ * separator has to survive a Stripe session id, which already contains `_`.
132
+ * Firestore reserves ids fully matching `__.*__`; this never is, because all
133
+ * three parts are non-empty and the id neither starts nor ends with `__`.
134
+ */ export function supplierDeliveryId(hostId, orderId, supplierId) {
135
+ return `${hostId}__${orderId}__${supplierId}`;
136
+ }
137
+ /**
138
+ * Records that a supplier POST is owed. One Firestore write, awaited.
139
+ *
140
+ * Returns `'queued'`, `'exists'` when a row for this triple is already in
141
+ * flight, or `'skipped'`. NEVER THROWS: the caller is a paid order's fulfilment
142
+ * path, and a queue that cannot be written must not take the receipt down with
143
+ * it. The refusal is logged, which is strictly more than the old code managed
144
+ * on the same failure.
145
+ */ export async function enqueueSupplierDelivery(options) {
146
+ var _options_now;
147
+ const { firestore, hostId, orderId, supplierId, supplierName, url, body } = options;
148
+ const now = (_options_now = options.now) != null ? _options_now : Date.now();
149
+ const id = supplierDeliveryId(hostId, orderId, supplierId);
150
+ if (!isDocumentId(id)) {
151
+ console.error('Supplier delivery not queued: unusable id', id);
152
+ return 'skipped';
153
+ }
154
+ const record = {
155
+ status: 'pending',
156
+ hostId,
157
+ orderId,
158
+ supplierId,
159
+ supplierName,
160
+ url,
161
+ body,
162
+ attempts: 0,
163
+ // Due immediately: the next beat picks it up, at most a minute out.
164
+ nextAttemptAtMs: now,
165
+ createdAtMs: now
166
+ };
167
+ try {
168
+ await firestore.collection(SUPPLIER_DELIVERY_COLLECTION).doc(id).create(record);
169
+ return 'queued';
170
+ } catch (error) {
171
+ if ((error == null ? void 0 : error.code) === GRPC_ALREADY_EXISTS) {
172
+ return 'exists';
173
+ }
174
+ console.error('Supplier delivery not queued', hostId, orderId, error);
175
+ return 'skipped';
176
+ }
177
+ }
178
+ /**
179
+ * Stamps a routing failure on the order the merchant actually reads.
180
+ *
181
+ * `update()`, not a merge-set, for `recordRedemptionOrphan`'s reason: the order
182
+ * exists — the delivery was queued from its own fulfilment — and a merge would
183
+ * mint an order stub on the one path where it does not.
184
+ */ async function stampOrderRoutingFailure(firestore, hostId, orderId, detail) {
185
+ if (!isDocumentId(hostId) || !isDocumentId(orderId)) return;
186
+ await firestore.collection('hosts').doc(hostId).collection('orders').doc(orderId).update({
187
+ timeline: firebaseAdmin.firestore.FieldValue.arrayUnion({
188
+ atMs: Date.now(),
189
+ event: 'routing-failed',
190
+ detail
191
+ })
192
+ }).catch(()=>undefined);
193
+ }
194
+ /**
195
+ * One delivery attempt.
196
+ *
197
+ * Never throws: the drain is a shared beat, and one merchant's supplier must
198
+ * not abort every other merchant's queue — the `process-restock.ts` lesson,
199
+ * where a single poisoned row killed back-in-stock email platform-wide.
200
+ */ async function attemptSupplierDelivery(firestore, snapshot, now) {
201
+ var _data_hostId, _data_attempts, _data_supplierId, _supplierSnapshot_get, _supplierSnapshot_get1, _data_body;
202
+ const data = snapshot.data();
203
+ const hostId = String((_data_hostId = data.hostId) != null ? _data_hostId : '');
204
+ const attempts = Number((_data_attempts = data.attempts) != null ? _data_attempts : 0) + 1;
205
+ const retire = async ()=>{
206
+ await snapshot.ref.delete().catch(()=>undefined);
207
+ return 'cancelled';
208
+ };
209
+ if (!isDocumentId(hostId) || !isDocumentId(String((_data_supplierId = data.supplierId) != null ? _data_supplierId : ''))) {
210
+ return retire();
211
+ }
212
+ // The endpoint and the secret are read FRESH rather than frozen into the row:
213
+ // a merchant correcting a typo'd URL corrects what is already queued, and the
214
+ // supplier's shared secret is never copied into a second document.
215
+ const supplierSnapshot = await firestore.collection('hosts').doc(hostId).collection('suppliers').doc(String(data.supplierId)).get().catch(()=>null);
216
+ // A read that FAILED is not a supplier that is gone. Retrying beats retiring
217
+ // a real delivery on a transient Firestore error — the `reconcile-stock.ts`
218
+ // rule that a failed read is not an absent marker.
219
+ if (!supplierSnapshot) {
220
+ return recordFailure(firestore, snapshot, data, attempts, now, 'could not read the supplier record', undefined);
221
+ }
222
+ const url = String((_supplierSnapshot_get = supplierSnapshot.get('webhookUrl')) != null ? _supplierSnapshot_get : '');
223
+ if (!url) {
224
+ // Deliberately NOT a dead letter: the merchant removed the endpoint (or the
225
+ // supplier), which is a decision rather than an outage. Alarming them about
226
+ // a delivery they cancelled is how an alert stops being read.
227
+ return retire();
228
+ }
229
+ const secret = String((_supplierSnapshot_get1 = supplierSnapshot.get('webhookSecret')) != null ? _supplierSnapshot_get1 : '');
230
+ const body = String((_data_body = data.body) != null ? _data_body : '');
231
+ let status;
232
+ try {
233
+ var _ref;
234
+ const response = await fetch(url, {
235
+ method: 'POST',
236
+ headers: _extends({
237
+ 'Content-Type': 'application/json'
238
+ }, secret ? {
239
+ 'x-aglyn-signature': createHmac('sha256', secret).update(body).digest('hex')
240
+ } : {}),
241
+ body,
242
+ signal: AbortSignal.timeout(SUPPLIER_DELIVERY_TIMEOUT_MS)
243
+ });
244
+ status = Number((_ref = response == null ? void 0 : response.status) != null ? _ref : 0);
245
+ if (!(response == null ? void 0 : response.ok)) {
246
+ return recordFailure(firestore, snapshot, data, attempts, now, `supplier answered HTTP ${status}`, status);
247
+ }
248
+ } catch (error) {
249
+ var _ref1;
250
+ return recordFailure(firestore, snapshot, data, attempts, now, String((_ref1 = error == null ? void 0 : error.message) != null ? _ref1 : error), undefined);
251
+ }
252
+ // Delivered rows are DELETED rather than stamped — see the module note: the
253
+ // body holds the buyer's email and name, and a top-level document is outside
254
+ // the recursive delete an erasure request runs over `hosts/{hostId}`.
255
+ await snapshot.ref.delete().catch(()=>undefined);
256
+ return 'delivered';
257
+ }
258
+ /** Books one failure: another retry, or the dead letter and its two alarms. */ async function recordFailure(firestore, snapshot, data, attempts, now, reason, status) {
259
+ var _data_hostId, _data_orderId, _data_supplierName;
260
+ const exhausted = attempts >= SUPPLIER_DELIVERY_MAX_ATTEMPTS;
261
+ await snapshot.ref.update(_extends({
262
+ status: exhausted ? 'failed' : 'pending',
263
+ attempts,
264
+ lastError: reason
265
+ }, status ? {
266
+ lastStatus: status
267
+ } : {}, exhausted ? {
268
+ failedAtMs: now
269
+ } : {
270
+ nextAttemptAtMs: now + supplierDeliveryBackoffMs(attempts)
271
+ })).catch(()=>undefined);
272
+ if (!exhausted) return 'retried';
273
+ const hostId = String((_data_hostId = data.hostId) != null ? _data_hostId : '');
274
+ const orderId = String((_data_orderId = data.orderId) != null ? _data_orderId : '');
275
+ const supplierName = String((_data_supplierName = data.supplierName) != null ? _data_supplierName : '') || 'the supplier';
276
+ await stampOrderRoutingFailure(firestore, hostId, orderId, `Could not reach ${supplierName} after ${attempts} attempts ` + `(${reason}). This order was never routed.`);
277
+ // The bell as well as the timeline: nobody opens an order they have no
278
+ // reason to suspect.
279
+ await notifyHostManagers(hostId, {
280
+ type: 'content.order',
281
+ title: `Order not routed to ${supplierName}`,
282
+ body: `Order ${orderId} could not be sent after ${attempts} attempts.`,
283
+ link: `/${hostId}/products`
284
+ }).catch(()=>undefined);
285
+ return 'dead-lettered';
286
+ }
287
+ /**
288
+ * Drains the supplier outbox. Bounded, and safe to run twice.
289
+ *
290
+ * `nextAttemptAtMs` is filtered IN MEMORY rather than added to the query, which
291
+ * would need a composite index for one field's worth of selectivity. The cost
292
+ * is that a row still inside its backoff occupies one of the
293
+ * {@link SUPPLIER_DELIVERY_SCAN_LIMIT} slots; with at most
294
+ * {@link SUPPLIER_DELIVERY_MAX_ATTEMPTS} attempts per row the queue always
295
+ * drains rather than growing a permanent head.
296
+ */ export async function scanSupplierDeliveries(/** The lockdown gate, injected by the caller (AGL-2495). Not optional. */ gate, now = Date.now()) {
297
+ const firestore = firebaseAdmin.app().firestore();
298
+ const pending = await firestore.collection(SUPPLIER_DELIVERY_COLLECTION).where('status', '==', 'pending').limit(SUPPLIER_DELIVERY_SCAN_LIMIT).get();
299
+ const result = {
300
+ scanned: pending.size,
301
+ delivered: 0,
302
+ retried: 0,
303
+ deadLettered: 0,
304
+ cancelled: 0,
305
+ skippedLocked: 0
306
+ };
307
+ for (const snapshot of pending.docs){
308
+ var _ref, _ref1;
309
+ const data = snapshot.data();
310
+ // LOCKDOWN (AGL-2495). The row is a TOP-LEVEL document carrying its own
311
+ // `hostId` rather than living under `hosts/{hostId}`, so the host is read
312
+ // from the record instead of the parent chain — the one job of the six
313
+ // whose subject is not in its path.
314
+ //
315
+ // An outbound POST to the merchant's supplier is this platform acting in
316
+ // a suspended merchant's name against a third party, which is precisely
317
+ // what a takedown is for. The attempt also mutates the row (`attempts`,
318
+ // `nextAttemptAtMs`, or the dead-letter) and can notify the host's
319
+ // managers.
320
+ //
321
+ // SKIPPED, NOT DROPPED, and the strongest case of the six: the row stays
322
+ // `pending` with its `attempts` count untouched, so a long lock cannot
323
+ // burn a paid order's retry budget and dead-letter it for being locked.
324
+ // The queue drains from where it stood the minute the lock lifts.
325
+ if (await gate.isLocked(String((_ref = data == null ? void 0 : data.hostId) != null ? _ref : ''))) {
326
+ result.skippedLocked += 1;
327
+ continue;
328
+ }
329
+ if (Number((_ref1 = data == null ? void 0 : data.nextAttemptAtMs) != null ? _ref1 : 0) > now) continue;
330
+ const outcome = await attemptSupplierDelivery(firestore, snapshot, now).catch((error)=>{
331
+ console.error('Supplier delivery attempt failed', snapshot.ref.path, error);
332
+ return null;
333
+ });
334
+ if (outcome === 'delivered') result.delivered += 1;
335
+ else if (outcome === 'retried') result.retried += 1;
336
+ else if (outcome === 'dead-lettered') result.deadLettered += 1;
337
+ else if (outcome === 'cancelled') result.cancelled += 1;
338
+ }
339
+ return result;
340
+ }
341
+
342
+ //# sourceMappingURL=supplier-outbox.js.map