@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,146 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import { notifyHostManagers } from "@aglyn/tenant-data-admin";
18
+ import * as CommerceModel from "../model/index.js";
19
+ /**
20
+ * Decrements one variant's stock inside a transaction and reports what the
21
+ * shelf could actually give up. Never throws: a stock write must not fail a
22
+ * webhook, because Stripe would redeliver and the order would be minted twice.
23
+ *
24
+ * ## THE LEDGER ROW RIDES INSIDE THE TRANSACTION (AGL-2161)
25
+ *
26
+ * The count and its `inventoryAdjustments` row used to be two separate writes
27
+ * at six call sites, the second one a bare
28
+ * `.add({…}).catch(() => undefined)`. Either could land without the other and
29
+ * nothing anywhere said so:
30
+ *
31
+ * - **row lost, count moved** — `cancel-order.ts:206-224` reads the rows for
32
+ * an order to decide whether a POS card sale was ever decremented, and reads
33
+ * `appliedDelta ?? delta` to cap the restock. No row means it refuses to
34
+ * release that stock at all, so the units are stranded permanently.
35
+ * - **count lost, row written** — the reverse hands back units nobody has, the
36
+ * failure `StockDecrementOutcome.failed` already exists to prevent.
37
+ *
38
+ * Both targets hang off the same `hostRef`, so nothing ever stopped them
39
+ * sharing one transaction; they simply did not. They do now, and the divergence
40
+ * is not made *loud*, it is made **impossible** — which is the stronger of the
41
+ * two options, and available here only because the helper already owned the
42
+ * transaction the count was written in.
43
+ *
44
+ * Consequences worth stating, because they change five call sites at once:
45
+ *
46
+ * - A ledger failure now ROLLS BACK the decrement instead of being swallowed.
47
+ * That is the direction that keeps the two readings in agreement: the sale
48
+ * is still paid, the shelf is untouched, and `reconcile-stock.ts` reports a
49
+ * missing decrement — which is true, and was previously a false positive
50
+ * whenever only the row was lost.
51
+ * - The row is still auto-id'd. A deterministic id keyed on the order would
52
+ * make redelivery idempotent, but two lines of one product in one order are
53
+ * two legitimate rows (`billing-webhook-low-stock.spec.ts`, "logs both sale
54
+ * rows"), and a deterministic key would silently fold them into one and
55
+ * under-cap the restock. Redelivery stays bounded upstream, where it was.
56
+ */ export async function decrementVariantStock(options) {
57
+ const { firestore, hostRef, hostId, productId, variantId, quantity, locationId, ledger } = options;
58
+ const requested = -Math.abs(Math.round(Number(quantity) || 0));
59
+ const nothing = {
60
+ applied: 0,
61
+ requested,
62
+ before: null,
63
+ after: null,
64
+ failed: false
65
+ };
66
+ if (requested === 0) return nothing;
67
+ let outcome;
68
+ try {
69
+ outcome = await firestore.runTransaction(async (transaction)=>{
70
+ const productRef = hostRef.collection('products').doc(productId);
71
+ const snapshot = await transaction.get(productRef);
72
+ if (!(snapshot == null ? void 0 : snapshot.exists)) return nothing;
73
+ const before = CommerceModel.liftLegacyProduct(snapshot.data());
74
+ const tracked = before.variants.some((variant)=>variant.id === variantId && variant.inventory != null);
75
+ if (!tracked) return nothing;
76
+ const variants = CommerceModel.adjustVariantInventory(before, variantId, requested, locationId);
77
+ // Computed from the SAME read the write is derived from, inside the same
78
+ // transaction — which is the whole point (AGL-2320).
79
+ const applied = CommerceModel.appliedVariantInventoryDelta(before, variantId, requested, locationId);
80
+ const after = _extends({}, before, {
81
+ variants
82
+ });
83
+ transaction.set(productRef, {
84
+ variants,
85
+ inventory: CommerceModel.productInventory(after)
86
+ }, {
87
+ merge: true
88
+ });
89
+ // Same transaction, so the count and the row commit together or neither
90
+ // does (AGL-2161). `applied` is the figure computed above from the read
91
+ // this write is derived from, so `appliedDelta` tells the truth under
92
+ // contention exactly as it does for the count.
93
+ if (ledger) {
94
+ transaction.set(hostRef.collection('inventoryAdjustments').doc(), _extends({
95
+ productId,
96
+ variantId,
97
+ delta: requested
98
+ }, applied !== requested ? {
99
+ appliedDelta: applied
100
+ } : {}, {
101
+ reason: ledger.reason,
102
+ orderId: ledger.orderId
103
+ }, locationId ? {
104
+ locationId
105
+ } : {}, {
106
+ atMs: Date.now()
107
+ }));
108
+ }
109
+ return {
110
+ applied,
111
+ requested,
112
+ before,
113
+ after,
114
+ failed: false
115
+ };
116
+ });
117
+ } catch (error) {
118
+ // Swallowed like the `.catch(() => undefined)` this replaces, but no longer
119
+ // silently: the caller skips its ledger row, and the count and the ledger
120
+ // stay in agreement about a decrement that did not happen.
121
+ console.error('Stock decrement failed', hostId, productId, variantId, error);
122
+ return _extends({}, nothing, {
123
+ failed: true
124
+ });
125
+ }
126
+ // The oversell is now LOUD (AGL-2320). `content.lowStock` is deliberately
127
+ // reused rather than a new notification type: the type union carries a label
128
+ // map, a category and a per-user mute, and "you are out of this" is the
129
+ // category a merchant who cares about stock is already subscribed to. A
130
+ // backorder product selling past zero
131
+ // is the merchant's own choice and already understood (AGL-2149), so only a
132
+ // deny-policy shortfall is reported — that is the one the merchant did not
133
+ // ask for and previously got no signal about at all.
134
+ const short = outcome.applied - outcome.requested;
135
+ if (short > 0 && outcome.before && outcome.before.oversellPolicy !== 'backorder') {
136
+ void notifyHostManagers(hostId, {
137
+ type: 'content.lowStock',
138
+ title: `Oversold — ${outcome.before.name}`,
139
+ body: `${Math.abs(outcome.requested)} sold, ${Math.abs(outcome.applied)} ` + `came off the shelf. ${short} unit${short === 1 ? '' : 's'} were not ` + 'in stock — the sale is paid and needs restocking or refunding.',
140
+ link: `/${hostId}/products`
141
+ });
142
+ }
143
+ return outcome;
144
+ }
145
+
146
+ //# sourceMappingURL=reserve-stock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/reserve-stock.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 { notifyHostManagers } from '@aglyn/tenant-data-admin'\nimport * as CommerceModel from '../model'\n\n/**\n * THE ATOMIC STOCK DECREMENT (AGL-2320).\n *\n * Every stock write in this plugin was a read → compute → `set(…, {merge:true})`\n * of the whole `variants` array, with the read often far upstream of the write:\n * the cart branch of `billing-webhook.ts` reads its products, then runs a\n * transaction, a `cartRef.delete()`, a checkout-doc read, licence-key\n * assignment and an email send before it decrements. Two sales landing in that\n * window both computed from the same `variants` and both wrote; the later won\n * and one decrement was LOST. The ledger showed two `sale` rows while the count\n * moved once, so the shelf was short by one and the storefront went on offering\n * the unit it had already sold — the loss compounds, because phantom stock is\n * what admits the next oversell.\n *\n * `inventory` lives INSIDE the `variants` array, not at a document field path,\n * so `FieldValue.increment` is not expressible against it. That is why this was\n * filed as blocked on a data-model change. It is not the only way to make a\n * decrement safe: a transaction is. `Transaction.get()` takes a lock on the\n * product document, so two concurrent decrements SERIALIZE — the loser re-runs\n * its callback against the winner's committed state and subtracts from the real\n * remainder. The read-modify-write stays, the schema is untouched, and no\n * migration is needed. The cost is one contended retry, not one extra read.\n *\n * WHAT THIS DOES NOT DO. It does not refuse a sale. Every storefront path\n * gates on `canPurchase` when the Stripe Checkout session is created and\n * decrements minutes later in the webhook, by which time the money has moved —\n * refusing there would take payment and withhold goods. Closing the last-unit\n * oversell needs a HOLD taken at session creation and released when the session\n * expires, which is a feature with a new failure mode (an abandoned cart\n * sitting on the last unit for the session's lifetime) and is deliberately not\n * being introduced days before launch. So the oversell is made LOUD instead of\n * silent: when the fresh read proves the shelf could not cover the sale, the\n * managers are told, with the number that was actually short.\n *\n * The floor in `adjustVariantInventory` stays — a shelf count does not go\n * negative, and every reader assumes it cannot (AGL-2149). What changes is that\n * `applied` is now computed from the state the write actually lands on, so the\n * ledger's `appliedDelta` tells the truth under concurrency. Before this, two\n * concurrent sales of one unit each computed `appliedDelta: -1` from the same\n * stale `inventory: 1`, and the ledger claimed two units left a shelf that only\n * ever held one.\n */\nexport interface StockDecrementOutcome {\n /**\n * What the count ACTUALLY moved by — zero or negative, and never more than\n * the shelf held. The caller writes this as the ledger row's `appliedDelta`\n * (AGL-2149) when it differs from `requested`.\n */\n applied: number\n /** The units sold, negated. */\n requested: number\n /**\n * The product as read INSIDE the transaction, and the same product with the\n * committed variants. Both null when nothing was written — a missing product,\n * an untracked variant, or a failed commit. Handed to\n * `alertLowStockCrossing` as the pre/post pair, which is now the pair the\n * write actually crossed rather than one computed from an upstream read.\n */\n before: CommerceModel.HostProduct | null\n after: CommerceModel.HostProduct | null\n /**\n * The commit did not land. Distinct from `applied === 0`, which is a real\n * outcome (a deny-policy product already at zero). A caller must not write a\n * ledger row for a failed commit: a row whose count never moved is exactly\n * what makes a later cancellation hand back units nobody has.\n */\n failed: boolean\n}\n\n/**\n * What the ledger row joins this movement to (AGL-2161).\n *\n * Passing this is what makes the count and the row ONE write. Omitting it\n * decrements without a row, which only `reserve-stock`'s own specs do — every\n * production caller passes it, and `stock-decrement-race.spec.ts` fails the\n * build if one stops.\n */\nexport interface StockLedgerJoin {\n /** Why the count moved. Every sale path passes `sale`. */\n reason: CommerceModel.InventoryAdjustmentReason\n /**\n * The document this movement is answerable to. `cancel-order.ts` queries\n * `where('orderId','==',…)` to decide whether to restock at all, so a row\n * that names the wrong id is as bad as a missing one.\n */\n orderId: string\n}\n\n/**\n * Decrements one variant's stock inside a transaction and reports what the\n * shelf could actually give up. Never throws: a stock write must not fail a\n * webhook, because Stripe would redeliver and the order would be minted twice.\n *\n * ## THE LEDGER ROW RIDES INSIDE THE TRANSACTION (AGL-2161)\n *\n * The count and its `inventoryAdjustments` row used to be two separate writes\n * at six call sites, the second one a bare\n * `.add({…}).catch(() => undefined)`. Either could land without the other and\n * nothing anywhere said so:\n *\n * - **row lost, count moved** — `cancel-order.ts:206-224` reads the rows for\n * an order to decide whether a POS card sale was ever decremented, and reads\n * `appliedDelta ?? delta` to cap the restock. No row means it refuses to\n * release that stock at all, so the units are stranded permanently.\n * - **count lost, row written** — the reverse hands back units nobody has, the\n * failure `StockDecrementOutcome.failed` already exists to prevent.\n *\n * Both targets hang off the same `hostRef`, so nothing ever stopped them\n * sharing one transaction; they simply did not. They do now, and the divergence\n * is not made *loud*, it is made **impossible** — which is the stronger of the\n * two options, and available here only because the helper already owned the\n * transaction the count was written in.\n *\n * Consequences worth stating, because they change five call sites at once:\n *\n * - A ledger failure now ROLLS BACK the decrement instead of being swallowed.\n * That is the direction that keeps the two readings in agreement: the sale\n * is still paid, the shelf is untouched, and `reconcile-stock.ts` reports a\n * missing decrement — which is true, and was previously a false positive\n * whenever only the row was lost.\n * - The row is still auto-id'd. A deterministic id keyed on the order would\n * make redelivery idempotent, but two lines of one product in one order are\n * two legitimate rows (`billing-webhook-low-stock.spec.ts`, \"logs both sale\n * rows\"), and a deterministic key would silently fold them into one and\n * under-cap the restock. Redelivery stays bounded upstream, where it was.\n */\nexport async function decrementVariantStock(options: {\n firestore: any\n hostRef: any\n hostId: string\n productId: string\n variantId: string\n /** Units sold; sign is ignored. */\n quantity: number\n locationId?: string\n /**\n * The ledger row to write in the SAME transaction as the count (AGL-2161).\n * Omit only where no movement should be recorded.\n */\n ledger?: StockLedgerJoin\n}): Promise<StockDecrementOutcome> {\n const {\n firestore,\n hostRef,\n hostId,\n productId,\n variantId,\n quantity,\n locationId,\n ledger,\n } = options\n const requested = -Math.abs(Math.round(Number(quantity) || 0))\n const nothing: StockDecrementOutcome = {\n applied: 0,\n requested,\n before: null,\n after: null,\n failed: false,\n }\n if (requested === 0) return nothing\n let outcome: StockDecrementOutcome\n try {\n outcome = await firestore.runTransaction(async (transaction: any) => {\n const productRef = hostRef.collection('products').doc(productId)\n const snapshot = await transaction.get(productRef)\n if (!snapshot?.exists) return nothing\n const before = CommerceModel.liftLegacyProduct(snapshot.data() as any)\n const tracked = before.variants.some(\n (variant) => variant.id === variantId && variant.inventory != null,\n )\n if (!tracked) return nothing\n const variants = CommerceModel.adjustVariantInventory(\n before,\n variantId,\n requested,\n locationId,\n )\n // Computed from the SAME read the write is derived from, inside the same\n // transaction — which is the whole point (AGL-2320).\n const applied = CommerceModel.appliedVariantInventoryDelta(\n before,\n variantId,\n requested,\n locationId,\n )\n const after = { ...before, variants }\n transaction.set(\n productRef,\n {\n variants,\n inventory: CommerceModel.productInventory(after),\n },\n { merge: true },\n )\n // Same transaction, so the count and the row commit together or neither\n // does (AGL-2161). `applied` is the figure computed above from the read\n // this write is derived from, so `appliedDelta` tells the truth under\n // contention exactly as it does for the count.\n if (ledger) {\n transaction.set(\n hostRef.collection('inventoryAdjustments').doc(),\n {\n productId,\n variantId,\n delta: requested,\n ...(applied !== requested ? { appliedDelta: applied } : {}),\n reason: ledger.reason,\n orderId: ledger.orderId,\n ...(locationId ? { locationId } : {}),\n atMs: Date.now(),\n } satisfies CommerceModel.InventoryAdjustment,\n )\n }\n return { applied, requested, before, after, failed: false }\n })\n } catch (error) {\n // Swallowed like the `.catch(() => undefined)` this replaces, but no longer\n // silently: the caller skips its ledger row, and the count and the ledger\n // stay in agreement about a decrement that did not happen.\n console.error('Stock decrement failed', hostId, productId, variantId, error)\n return { ...nothing, failed: true }\n }\n // The oversell is now LOUD (AGL-2320). `content.lowStock` is deliberately\n // reused rather than a new notification type: the type union carries a label\n // map, a category and a per-user mute, and \"you are out of this\" is the\n // category a merchant who cares about stock is already subscribed to. A\n // backorder product selling past zero\n // is the merchant's own choice and already understood (AGL-2149), so only a\n // deny-policy shortfall is reported — that is the one the merchant did not\n // ask for and previously got no signal about at all.\n const short = outcome.applied - outcome.requested\n if (\n short > 0 &&\n outcome.before &&\n outcome.before.oversellPolicy !== 'backorder'\n ) {\n void notifyHostManagers(hostId, {\n type: 'content.lowStock',\n title: `Oversold — ${outcome.before.name}`,\n body:\n `${Math.abs(outcome.requested)} sold, ${Math.abs(outcome.applied)} ` +\n `came off the shelf. ${short} unit${short === 1 ? '' : 's'} were not ` +\n 'in stock — the sale is paid and needs restocking or refunding.',\n link: `/${hostId}/products`,\n })\n }\n return outcome\n}\n"],"names":["notifyHostManagers","CommerceModel","decrementVariantStock","options","firestore","hostRef","hostId","productId","variantId","quantity","locationId","ledger","requested","Math","abs","round","Number","nothing","applied","before","after","failed","outcome","runTransaction","transaction","productRef","collection","doc","snapshot","get","exists","liftLegacyProduct","data","tracked","variants","some","variant","id","inventory","adjustVariantInventory","appliedVariantInventoryDelta","set","productInventory","merge","delta","appliedDelta","reason","orderId","atMs","Date","now","error","console","short","oversellPolicy","type","title","name","body","link"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,kBAAkB,QAAQ,2BAA0B;AAC7D,YAAYC,mBAAmB,oBAAU;AA0FzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCC,GACD,OAAO,eAAeC,sBAAsBC,OAc3C;IACC,MAAM,EACJC,SAAS,EACTC,OAAO,EACPC,MAAM,EACNC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,UAAU,EACVC,MAAM,EACP,GAAGR;IACJ,MAAMS,YAAY,CAACC,KAAKC,GAAG,CAACD,KAAKE,KAAK,CAACC,OAAOP,aAAa;IAC3D,MAAMQ,UAAiC;QACrCC,SAAS;QACTN;QACAO,QAAQ;QACRC,OAAO;QACPC,QAAQ;IACV;IACA,IAAIT,cAAc,GAAG,OAAOK;IAC5B,IAAIK;IACJ,IAAI;QACFA,UAAU,MAAMlB,UAAUmB,cAAc,CAAC,OAAOC;YAC9C,MAAMC,aAAapB,QAAQqB,UAAU,CAAC,YAAYC,GAAG,CAACpB;YACtD,MAAMqB,WAAW,MAAMJ,YAAYK,GAAG,CAACJ;YACvC,IAAI,EAACG,4BAAAA,SAAUE,MAAM,GAAE,OAAOb;YAC9B,MAAME,SAASlB,cAAc8B,iBAAiB,CAACH,SAASI,IAAI;YAC5D,MAAMC,UAAUd,OAAOe,QAAQ,CAACC,IAAI,CAClC,CAACC,UAAYA,QAAQC,EAAE,KAAK7B,aAAa4B,QAAQE,SAAS,IAAI;YAEhE,IAAI,CAACL,SAAS,OAAOhB;YACrB,MAAMiB,WAAWjC,cAAcsC,sBAAsB,CACnDpB,QACAX,WACAI,WACAF;YAEF,yEAAyE;YACzE,qDAAqD;YACrD,MAAMQ,UAAUjB,cAAcuC,4BAA4B,CACxDrB,QACAX,WACAI,WACAF;YAEF,MAAMU,QAAQ,aAAKD;gBAAQe;;YAC3BV,YAAYiB,GAAG,CACbhB,YACA;gBACES;gBACAI,WAAWrC,cAAcyC,gBAAgB,CAACtB;YAC5C,GACA;gBAAEuB,OAAO;YAAK;YAEhB,wEAAwE;YACxE,wEAAwE;YACxE,sEAAsE;YACtE,+CAA+C;YAC/C,IAAIhC,QAAQ;gBACVa,YAAYiB,GAAG,CACbpC,QAAQqB,UAAU,CAAC,wBAAwBC,GAAG,IAC9C;oBACEpB;oBACAC;oBACAoC,OAAOhC;mBACHM,YAAYN,YAAY;oBAAEiC,cAAc3B;gBAAQ,IAAI,CAAC;oBACzD4B,QAAQnC,OAAOmC,MAAM;oBACrBC,SAASpC,OAAOoC,OAAO;mBACnBrC,aAAa;oBAAEA;gBAAW,IAAI,CAAC;oBACnCsC,MAAMC,KAAKC,GAAG;;YAGpB;YACA,OAAO;gBAAEhC;gBAASN;gBAAWO;gBAAQC;gBAAOC,QAAQ;YAAM;QAC5D;IACF,EAAE,OAAO8B,OAAO;QACd,4EAA4E;QAC5E,0EAA0E;QAC1E,2DAA2D;QAC3DC,QAAQD,KAAK,CAAC,0BAA0B7C,QAAQC,WAAWC,WAAW2C;QACtE,OAAO,aAAKlC;YAASI,QAAQ;;IAC/B;IACA,0EAA0E;IAC1E,6EAA6E;IAC7E,wEAAwE;IACxE,wEAAwE;IACxE,sCAAsC;IACtC,4EAA4E;IAC5E,2EAA2E;IAC3E,qDAAqD;IACrD,MAAMgC,QAAQ/B,QAAQJ,OAAO,GAAGI,QAAQV,SAAS;IACjD,IACEyC,QAAQ,KACR/B,QAAQH,MAAM,IACdG,QAAQH,MAAM,CAACmC,cAAc,KAAK,aAClC;QACA,KAAKtD,mBAAmBM,QAAQ;YAC9BiD,MAAM;YACNC,OAAO,CAAC,WAAW,EAAElC,QAAQH,MAAM,CAACsC,IAAI,EAAE;YAC1CC,MACE,GAAG7C,KAAKC,GAAG,CAACQ,QAAQV,SAAS,EAAE,OAAO,EAAEC,KAAKC,GAAG,CAACQ,QAAQJ,OAAO,EAAE,CAAC,CAAC,GACpE,CAAC,oBAAoB,EAAEmC,MAAM,KAAK,EAAEA,UAAU,IAAI,KAAK,IAAI,UAAU,CAAC,GACtE;YACFM,MAAM,CAAC,CAAC,EAAErD,OAAO,SAAS,CAAC;QAC7B;IACF;IACA,OAAOgB;AACT"}
@@ -0,0 +1,25 @@
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 { PluginApiHandler } from '@aglyn/aglyn/server';
18
+ /**
19
+ * Reserve a stay (AGL-310): server-side quote + availability check,
20
+ * pending reservation doc, then a Stripe session for the deposit (or
21
+ * full amount) on the merchant's account. Webhook completion confirms
22
+ * the reservation; abandoned pending holds expire after 30 minutes and
23
+ * stop blocking the calendar.
24
+ */
25
+ export declare const reserveHandler: PluginApiHandler;
@@ -0,0 +1,426 @@
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 * as Aglyn from "@aglyn/aglyn/server";
18
+ import * as CommerceModel from "../model/index.js";
19
+ import { claimAttempt } from "@aglyn/aglyn/server";
20
+ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
21
+ import { connectLinkageIsReady } from "@aglyn/tenant-data-admin/server/stripe-account-mode";
22
+ /**
23
+ * Reserve a stay (AGL-310): server-side quote + availability check,
24
+ * pending reservation doc, then a Stripe session for the deposit (or
25
+ * full amount) on the merchant's account. Webhook completion confirms
26
+ * the reservation; abandoned pending holds expire after 30 minutes and
27
+ * stop blocking the calendar.
28
+ */ export const reserveHandler = async (req, res)=>{
29
+ var _req_body, _body_hostId, _body_resourceId, _body_checkInDayMs, _body_checkOutDayMs, _body_guestName, _body_guestEmail, _ref, _req_headers_idempotencykey;
30
+ if (req.method !== 'POST') {
31
+ return res.status(405).json({
32
+ error: 'Method not allowed'
33
+ });
34
+ }
35
+ if (!process.env.STRIPE_SECRET_KEY) {
36
+ return res.status(501).json({
37
+ error: 'Payments are not configured.'
38
+ });
39
+ }
40
+ const body = typeof req.body === 'string' ? JSON.parse(req.body) : (_req_body = req.body) != null ? _req_body : {};
41
+ const hostId = String((_body_hostId = body.hostId) != null ? _body_hostId : '');
42
+ const resourceId = String((_body_resourceId = body.resourceId) != null ? _body_resourceId : '');
43
+ const checkInDayMs = CommerceModel.toDayMs(Number((_body_checkInDayMs = body.checkInDayMs) != null ? _body_checkInDayMs : 0));
44
+ const checkOutDayMs = CommerceModel.toDayMs(Number((_body_checkOutDayMs = body.checkOutDayMs) != null ? _body_checkOutDayMs : 0));
45
+ const guestName = String((_body_guestName = body.guestName) != null ? _body_guestName : '').trim().slice(0, 120);
46
+ const guestEmail = String((_body_guestEmail = body.guestEmail) != null ? _body_guestEmail : '').trim().toLowerCase().slice(0, 120);
47
+ // One reservation attempt, minted by the widget (AGL-1697). Node lowercases
48
+ // incoming headers, but read both spellings — the plugin API request type
49
+ // makes no promise about casing.
50
+ const idempotencyKey = String((_ref = (_req_headers_idempotencykey = req.headers['idempotency-key']) != null ? _req_headers_idempotencykey : req.headers['Idempotency-Key']) != null ? _ref : '').trim().slice(0, 200);
51
+ if (!hostId || !resourceId || !checkInDayMs || !checkOutDayMs) {
52
+ return res.status(400).json({
53
+ error: 'Missing reservation details'
54
+ });
55
+ }
56
+ let claim = null;
57
+ try {
58
+ var _ref1, _ref2, _req_headers_referer;
59
+ var _ownerOrg_org, _ownerOrg_org1, _storeSnapshot_data;
60
+ const firestore = firebaseAdmin.app().firestore();
61
+ const hostRef = firestore.collection('hosts').doc(hostId);
62
+ // Owner + payment readiness, HOISTED above the claim (AGL-1697): both are
63
+ // deterministic refusals a merchant fixes out of band, and neither should
64
+ // burn the guest's attempt key.
65
+ const ownerOrg = await getOrgForHost(hostId);
66
+ // Plan gate, re-asked per request exactly as the storefront checkout
67
+ // asks it (AGL-1873, the AGL-481 pattern): a lapsed org's storefront
68
+ // must not keep taking reservation deposits — at the free plan's 0%
69
+ // transaction fee — through the one shopper-facing commerce door that
70
+ // skipped the entitlement. Deterministic and merchant-side, so it sits
71
+ // here above the claim with the readiness check.
72
+ if (!Aglyn.checkEntitlement(ownerOrg == null ? void 0 : ownerOrg.org, 'commerce')) {
73
+ return res.status(403).json({
74
+ error: 'Reservations are not enabled'
75
+ });
76
+ }
77
+ const ownerId = ownerOrg == null ? void 0 : (_ownerOrg_org = ownerOrg.org) == null ? void 0 : _ownerOrg_org.ownerUid;
78
+ const ownerProfile = ownerId ? await firestore.collection('profiles').doc(String(ownerId)).get() : null;
79
+ const accountId = ownerProfile == null ? void 0 : ownerProfile.get('stripeAccountId');
80
+ if (!connectLinkageIsReady({
81
+ accountId,
82
+ chargesEnabled: ownerProfile == null ? void 0 : ownerProfile.get('stripeChargesEnabled'),
83
+ accountLivemode: ownerProfile == null ? void 0 : ownerProfile.get('stripeAccountLivemode')
84
+ }, {
85
+ subject: `reserve host ${hostId}`
86
+ })) {
87
+ return res.status(409).json({
88
+ error: 'Payments are not set up yet'
89
+ });
90
+ }
91
+ // The claim sits ABOVE the availability read, and that placement is the
92
+ // fix for this handler's particular lie (AGL-1697): a retried attempt used
93
+ // to collide with its OWN 30-minute pending hold and be told "Those dates
94
+ // just sold out" — about dates the guest was holding — where the correct
95
+ // answer was the original session URL. Replaying here means the retry
96
+ // never reaches the availability check at all. Every refusal below the
97
+ // claim releases it, because each is deterministic and retryable.
98
+ const claimed = await claimAttempt(firestore, {
99
+ kind: 'commerce-reserve',
100
+ scopeId: hostId,
101
+ orgId: String((_ref1 = ownerOrg == null ? void 0 : (_ownerOrg_org1 = ownerOrg.org) == null ? void 0 : _ownerOrg_org1.id) != null ? _ref1 : ''),
102
+ key: idempotencyKey,
103
+ busyMessage: 'This reservation is already being processed'
104
+ });
105
+ if ('replay' in claimed) {
106
+ return res.status(claimed.replay.status).json(claimed.replay.body);
107
+ }
108
+ claim = claimed.claim;
109
+ // ONLY STAYS THAT COULD STILL OVERLAP, NEAREST FIRST (AGL-2159).
110
+ //
111
+ // This was `.where('resourceId','==',resourceId).limit(500)` with no
112
+ // ordering, so Firestore returned 500 documents in `__name__` order — an
113
+ // arbitrary slice of the resource's ENTIRE booking history. Every stay the
114
+ // resource has ever had competed for those 500 slots on equal terms with
115
+ // the ones that matter, so a cottage that had taken 500 bookings began
116
+ // silently dropping LIVE reservations out of its own availability check
117
+ // and confirming a second guest into an occupied room. Nothing about that
118
+ // failure is visible: `isRangeAvailable` is handed a short list and
119
+ // answers, correctly, that the range is free.
120
+ //
121
+ // `checkOutDayMs > checkInDayMs` is the one inequality that removes the
122
+ // whole of the past — a stay that ended before the requested arrival
123
+ // cannot overlap it — and ordering by the same field puts the stays
124
+ // nearest the requested window at the front of the limit rather than
125
+ // whichever ones happen to sort early by id. Needs the composite index
126
+ // `reservations (resourceId ASC, checkOutDayMs ASC)`, added to
127
+ // `cloud/firebase-firestore.indexes.json` and pinned by
128
+ // `reserve-availability-indexes.spec.ts` — an equality plus an `orderBy`
129
+ // on a second field is exactly the shape that reads as free and is not
130
+ // (AGL-1793), and here a missing index throws rather than under-reporting.
131
+ //
132
+ // RESIDUAL, stated: the cap can still bite when a single resource holds
133
+ // more than 500 stays that all end between the requested arrival and the
134
+ // end of a genuinely overlapping one. That is a far narrower window than
135
+ // "500 bookings in this resource's lifetime", but it is not zero, and the
136
+ // sweep that would keep expired `pending` holds from filling those slots
137
+ // is a scheduled job this change does not add (see the commit).
138
+ const availabilityQuery = hostRef.collection('reservations').where('resourceId', '==', resourceId).where('checkOutDayMs', '>', checkInDayMs).orderBy('checkOutDayMs').limit(500);
139
+ const [resourceSnapshot, reservationsSnapshot, storeSnapshot] = await Promise.all([
140
+ hostRef.collection('resources').doc(resourceId).get(),
141
+ availabilityQuery.get(),
142
+ // The merchant's own lodging rate (AGL-1969). Read in the SAME round
143
+ // trip as the availability query rather than as a fourth sequential
144
+ // await — this path already runs three reads before it can answer, and
145
+ // a tax lookup is not a reason to make a guest wait for a fourth.
146
+ hostRef.collection('settings').doc('store').get()
147
+ ]);
148
+ const resource = resourceSnapshot.data();
149
+ if (!resource) {
150
+ await claim.release();
151
+ return res.status(404).json({
152
+ error: 'Unknown resource'
153
+ });
154
+ }
155
+ // Pending holds block for 30 minutes only, so abandoned checkouts
156
+ // release the dates. The lapse itself lives in
157
+ // `reservationHoldsDates`, which `isRangeAvailable` applies — this reads
158
+ // the fields that rule needs and leaves the rule to the model, so the
159
+ // storefront's date-picker cannot answer a different question from the
160
+ // door that takes the money.
161
+ //
162
+ // Extracted so the pre-read below and the re-read inside the booking
163
+ // transaction cannot drift apart (AGL-2450). Two copies of a filter that
164
+ // decides whether a room is free is exactly the shape where one of them
165
+ // quietly stops matching the other.
166
+ const readLive = (snapshot)=>snapshot.docs.map((docSnapshot)=>{
167
+ var _docSnapshot_get;
168
+ return {
169
+ checkInDayMs: Number(docSnapshot.get('checkInDayMs')),
170
+ checkOutDayMs: Number(docSnapshot.get('checkOutDayMs')),
171
+ status: String(docSnapshot.get('status')),
172
+ createdAtMs: Number((_docSnapshot_get = docSnapshot.get('createdAtMs')) != null ? _docSnapshot_get : 0)
173
+ };
174
+ });
175
+ const now = Date.now();
176
+ const live = readLive(reservationsSnapshot);
177
+ if (!CommerceModel.isRangeAvailable(resource, live, checkInDayMs, checkOutDayMs, now)) {
178
+ // A GENUINE sold-out (a keyed retry replayed before reaching here). The
179
+ // guest picks other dates or the blocking stay is cancelled; either way
180
+ // the key must survive the refusal.
181
+ await claim.release();
182
+ return res.status(409).json({
183
+ error: 'Those dates just sold out'
184
+ });
185
+ }
186
+ const quote = CommerceModel.computeReservationQuote(resource, checkInDayMs, checkOutDayMs);
187
+ if (quote.problem) {
188
+ await claim.release();
189
+ return res.status(400).json({
190
+ error: quote.problem
191
+ });
192
+ }
193
+ const chargeCents = quote.depositCents || quote.totalCents;
194
+ // NO DISCOUNT IS APPLIED HERE, AND THAT IS AN OPEN QUESTION RATHER THAN AN
195
+ // OVERSIGHT (AGL-305).
196
+ //
197
+ // `hosts/{hostId}/discounts` reaches the cart, buy-now, the draft-order
198
+ // payment link and the register. This door was deliberately left out,
199
+ // because unlike those four it does not take a payment for goods — it takes
200
+ // a DEPOSIT against a stay that is settled later, and "apply 10% off" has
201
+ // three different meanings against that shape:
202
+ //
203
+ // 1. Discount the STAY. `quote.totalCents` falls, the deposit falls with
204
+ // it because it is a percentage of the subtotal, and the balance falls
205
+ // too. This is the only reading that is actually a discount on the
206
+ // booking — and it reprices a merchant's lodging inventory from a
207
+ // storefront promo code, which is a larger claim than any of the four
208
+ // goods doors makes.
209
+ // 2. Discount the DEPOSIT only. Strictly worse than doing nothing: the
210
+ // balance is computed downstream as `totalCents - paidCents`, so every
211
+ // cent taken off at booking is billed straight back at check-out. The
212
+ // guest would be shown a discount and then charged for it, which is
213
+ // the silent-reversal shape this codebase refuses elsewhere.
214
+ // 3. Discount the BALANCE. Nothing visible at booking; the guest finds
215
+ // out at the register. A promotion nobody can see when they buy is not
216
+ // a promotion.
217
+ //
218
+ // What makes this a product decision and not an implementation one is that
219
+ // the balance is not collected by any door this repo can teach. It is read
220
+ // off the console's reservations card as `totalCents - paidCents` and
221
+ // collected BY A HUMAN at the till, so option 1 is the only one that
222
+ // survives the hand-off — and it survives it by changing the stay's stored
223
+ // price, which is the merchant's revenue basis and what their analytics,
224
+ // their folio and their register all read.
225
+ //
226
+ // The tax makes it sharper still. `lodgingTax` below is an occupancy rate,
227
+ // not a sales rate, and its basis here is already a STATED LIMITATION — it
228
+ // is charged on what is collected (the deposit) rather than on the stay.
229
+ // Layering a discount on top asks whether occupancy tax is owed on the
230
+ // discounted room rate or the gross one, which differs by jurisdiction, is
231
+ // the merchant's own regime to answer, and is not a question this handler
232
+ // can decide from a promo code.
233
+ //
234
+ // So: refusing to guess. A shopper who types a code here is not told it
235
+ // worked — this path never reads one, so there is nothing to fall through
236
+ // silently, which is the failure mode that mattered. When the owner picks
237
+ // a reading, option 1 is the one the machinery already supports: reduce
238
+ // `quote.subtotalCents` before the deposit is derived from it, and the
239
+ // deposit, the balance, the fee and the tax all follow without further
240
+ // change.
241
+ // LODGING TAX: the MERCHANT'S OWN RATE, off unless they set one
242
+ // (AGL-1969, answering the decision AGL-1953 recorded here).
243
+ //
244
+ // What this path used to do, and why it was only ever a holding position:
245
+ // it computed no tax in either store mode, on two stated grounds. The
246
+ // first is still true and is the reason for the shape below — a stay is
247
+ // not goods. The AGL-285 zone editor configures a SALES rate, lodging is
248
+ // an occupancy/hotel regime with its own rates, its own registration and
249
+ // its own return, and reading `rates[]` for a night would be confidently
250
+ // wrong rather than merely absent. Stripe Tax has the mirror problem: it
251
+ // needs a lodging tax code this handler does not send, so
252
+ // `automatic_tax` here would compute a goods rate on a room. Neither of
253
+ // those changes, and neither is used.
254
+ //
255
+ // What DID change is that the merchant now has a field of their own to
256
+ // answer in (`tax.lodging`), so "Aglyn does not know the right number"
257
+ // stops being a reason to collect nothing. They type the rate, we compute
258
+ // it, charge it, record it and stamp the regime; the settings card states
259
+ // plainly that determining what is owed and to whom is theirs. Aglyn
260
+ // takes no tax position here — this is the manual LODGING rate, which
261
+ // never touches Aglyn's registrations.
262
+ //
263
+ // ⚠️ This comment used to say "Terms §10.3 ... untouched by this". §10.3
264
+ // CHANGED on 2026-08-24 (AGL-1956): Aglyn accepts marketplace-facilitator
265
+ // status and new §10.7 makes storefront sales tax Aglyn's where it has a
266
+ // collection obligation. Lodging tax is still the merchant's, so this
267
+ // handler is unaffected — but §10.3 is no longer the authority for that.
268
+ //
269
+ // DEFAULT OFF, and that is load-bearing: `resolveFlatTaxCents` answers
270
+ // zero for an absent, zero, negative or out-of-range rate, so no existing
271
+ // reservation's charge moves because this shipped.
272
+ //
273
+ // THE BASIS IS WHAT IS CHARGED, AND THAT IS A STATED LIMITATION RATHER
274
+ // THAN AN ANSWER. `chargeCents` is `depositCents || totalCents`, so on a
275
+ // deposit-taking resource the tax collected here is the rate on the
276
+ // DEPOSIT, not on the stay. Whether a given jurisdiction wants occupancy
277
+ // tax on the full stay at booking, on the deposit only, or on redemption
278
+ // at check-out is a tax question, it differs by jurisdiction, and this
279
+ // code deliberately does NOT decide it — the amount the platform actually
280
+ // moves is the only basis available to it, the settings card says so in
281
+ // the merchant's own view, and the residual is on AGL-1969.
282
+ const taxSettings = (_ref2 = (_storeSnapshot_data = storeSnapshot.data()) == null ? void 0 : _storeSnapshot_data.tax) != null ? _ref2 : {};
283
+ const lodgingTax = CommerceModel.resolveFlatTaxCents(taxSettings.lodging, chargeCents, 'Lodging tax');
284
+ // Platform take PLUS Stripe's card cost at cost (AGL-2152). This is a
285
+ // destination charge, so Stripe debits its percentage plus 30¢ from the
286
+ // PLATFORM's balance; with the old take-only figure every tier carrying a
287
+ // 0% service rate paid Aglyn nothing and cost it that fee on each
288
+ // reservation.
289
+ //
290
+ // THE TWO BASES ARE NOW DIFFERENT NUMBERS (AGL-1969), and the split is
291
+ // AGL-2317's rule: the platform take is computed on the ITEMS — the stay
292
+ // — while Stripe's cost is passed through on the WHOLE charge, because
293
+ // that is what Stripe actually debits. Taking a percentage of the lodging
294
+ // tax would be taking a cut of the state's money, which no storefront
295
+ // path does. The previous single-argument form is what made this a real
296
+ // risk: it read as "the fee base is the charge" and would have silently
297
+ // started taxing the tax the moment a tax line appeared.
298
+ const feeCents = Aglyn.resolveTransactionFeeCents(ownerOrg == null ? void 0 : ownerOrg.org, 'service', chargeCents, chargeCents + lodgingTax.taxCents);
299
+ // THE HOLD IS TAKEN IN A TRANSACTION (AGL-2450).
300
+ //
301
+ // The check above is a fast refusal on a stale read, and on its own that is
302
+ // all it ever was: the availability query ran, the quote and the fee were
303
+ // computed, and only then did the hold land — so two guests requesting the
304
+ // same dates both read a reservation set that lacked the other's booking,
305
+ // both passed, and both got a `pending` row and a real payment. Nothing
306
+ // downstream caught it. The webhook's transaction guards double-CONFIRMATION
307
+ // of one booking against Stripe redelivery; it never re-asks availability,
308
+ // so both holds confirmed cleanly into two guests in one room.
309
+ //
310
+ // `claimAttempt` does not help either, and it is worth being explicit about
311
+ // why: it is keyed on the guest's own `Idempotency-Key`, so it dedupes
312
+ // retries of ONE attempt. Two different guests carry two different keys and
313
+ // never contend.
314
+ //
315
+ // Re-asking inside the transaction that writes is the whole guard — the
316
+ // same shape as `decrementVariantStock` (AGL-2320), and easier to justify
317
+ // here: the conflicting write lands BEFORE Stripe is contacted, so this
318
+ // door can legitimately refuse rather than take the money and withhold the
319
+ // room.
320
+ const reservationRef = hostRef.collection('reservations').doc();
321
+ const booked = await firestore.runTransaction(async (transaction)=>{
322
+ const fresh = await transaction.get(availabilityQuery);
323
+ // Re-timed, not reusing `now`: a transaction that retries under
324
+ // contention may run appreciably later, and the 30-minute pending window
325
+ // has to be measured from when this attempt actually commits.
326
+ if (!CommerceModel.isRangeAvailable(resource, readLive(fresh), checkInDayMs, checkOutDayMs, Date.now())) {
327
+ return false;
328
+ }
329
+ // `create()`, not `set()`: the ref is freshly minted, so an id collision
330
+ // is a bug rather than an overwrite to absorb silently.
331
+ transaction.create(reservationRef, {
332
+ resourceId,
333
+ status: 'pending',
334
+ checkInDayMs,
335
+ checkOutDayMs,
336
+ guestName: guestName || null,
337
+ guestEmail: guestEmail || null,
338
+ nights: quote.nights,
339
+ totalCents: quote.totalCents,
340
+ depositCents: quote.depositCents,
341
+ paidCents: 0,
342
+ createdAtMs: now
343
+ });
344
+ return true;
345
+ });
346
+ if (!booked) {
347
+ // Lost the race for these dates. Same refusal as the pre-read's, and the
348
+ // key survives it for the same reason: the guest picks other dates or the
349
+ // blocking stay is cancelled.
350
+ await claim.release();
351
+ return res.status(409).json({
352
+ error: 'Those dates just sold out'
353
+ });
354
+ }
355
+ const referer = String((_req_headers_referer = req.headers.referer) != null ? _req_headers_referer : '');
356
+ const origin = `https://${req.headers.host}`;
357
+ const backUrl = referer.startsWith('http') ? referer : origin;
358
+ const separator = backUrl.includes('?') ? '&' : '?';
359
+ const params = new URLSearchParams(_extends({
360
+ mode: 'payment',
361
+ 'line_items[0][quantity]': '1',
362
+ 'line_items[0][price_data][currency]': 'usd',
363
+ 'line_items[0][price_data][unit_amount]': String(chargeCents),
364
+ 'line_items[0][price_data][product_data][name]': `${resource.name} — ${quote.nights} night${quote.nights === 1 ? '' : 's'}${quote.depositCents && quote.depositCents < quote.totalCents ? ' (deposit)' : ''}`.slice(0, 120)
365
+ }, lodgingTax.taxCents > 0 ? {
366
+ 'line_items[1][quantity]': '1',
367
+ 'line_items[1][price_data][currency]': 'usd',
368
+ 'line_items[1][price_data][unit_amount]': String(lodgingTax.taxCents),
369
+ 'line_items[1][price_data][product_data][name]': lodgingTax.label
370
+ } : {}, feeCents > 0 ? {
371
+ 'payment_intent_data[application_fee_amount]': String(feeCents)
372
+ } : {}, {
373
+ 'payment_intent_data[transfer_data][destination]': String(accountId)
374
+ }, guestEmail ? {
375
+ customer_email: guestEmail
376
+ } : {}, {
377
+ success_url: `${backUrl}${separator}reserved=1`,
378
+ cancel_url: `${backUrl}${separator}reserved=0`,
379
+ 'metadata[type]': 'commerce-reservation',
380
+ 'metadata[hostId]': hostId,
381
+ 'metadata[reservationId]': reservationRef.id,
382
+ 'metadata[feeCents]': String(feeCents)
383
+ }, lodgingTax.taxCents > 0 ? {
384
+ 'metadata[taxCents]': String(lodgingTax.taxCents),
385
+ 'metadata[taxPct]': String(lodgingTax.pct)
386
+ } : {}));
387
+ const response = await fetch('https://api.stripe.com/v1/checkout/sessions', {
388
+ method: 'POST',
389
+ headers: _extends({
390
+ Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,
391
+ 'Content-Type': 'application/x-www-form-urlencoded'
392
+ }, claim.stripeKey ? {
393
+ 'Idempotency-Key': claim.stripeKey
394
+ } : {}),
395
+ body: params.toString()
396
+ });
397
+ const session = await response.json();
398
+ if (!response.ok || !session.url) {
399
+ console.error('Stripe reservation error', session.error);
400
+ await reservationRef.delete().catch(()=>undefined);
401
+ // The hold is rolled back, so the key must come back too — the guest
402
+ // presses the same button and the retry re-derives the same digest,
403
+ // which Stripe replays if the session did get created.
404
+ await claim.release();
405
+ return res.status(502).json({
406
+ error: 'Payment setup failed'
407
+ });
408
+ }
409
+ const payload = {
410
+ url: session.url
411
+ };
412
+ await claim.record(200, payload);
413
+ return res.status(200).json(payload);
414
+ } catch (error) {
415
+ console.error(error);
416
+ // Release on the way out so a transient failure does not strand the key
417
+ // (AGL-1691's rule): the hold may or may not have landed, and it expires
418
+ // in 30 minutes either way.
419
+ await (claim == null ? void 0 : claim.release());
420
+ return res.status(500).json({
421
+ error: 'Reservation failed'
422
+ });
423
+ }
424
+ };
425
+
426
+ //# sourceMappingURL=reserve.js.map