@aglyn/plugins-commerce 1.0.0-beta.230 → 1.0.0-beta.232

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 (609) hide show
  1. package/package.json +13 -13
  2. package/src/index.d.ts +0 -1
  3. package/src/index.js +0 -1
  4. package/src/index.js.map +1 -1
  5. package/src/lib/barcode/barcode-decode.d.ts +71 -0
  6. package/src/lib/barcode/barcode-decode.js +498 -0
  7. package/src/lib/barcode/barcode-decode.js.map +1 -0
  8. package/src/lib/barcode/barcode-encode.d.ts +44 -0
  9. package/src/lib/barcode/barcode-encode.js +138 -0
  10. package/src/lib/barcode/barcode-encode.js.map +1 -0
  11. package/src/lib/barcode/barcode-scanner.component.d.ts +23 -0
  12. package/src/lib/barcode/barcode-scanner.component.js +260 -0
  13. package/src/lib/barcode/barcode-scanner.component.js.map +1 -0
  14. package/src/lib/barcode/scan-button.component.d.ts +10 -0
  15. package/src/lib/barcode/scan-button.component.js +62 -0
  16. package/src/lib/barcode/scan-button.component.js.map +1 -0
  17. package/src/lib/barcode/scanner-wedge.d.ts +35 -0
  18. package/src/lib/barcode/scanner-wedge.js +108 -0
  19. package/src/lib/barcode/scanner-wedge.js.map +1 -0
  20. package/src/lib/components/account.js +10 -1
  21. package/src/lib/components/account.js.map +1 -1
  22. package/src/lib/components/cart-extras.d.ts +45 -0
  23. package/src/lib/components/cart-extras.js +127 -0
  24. package/src/lib/components/cart-extras.js.map +1 -0
  25. package/src/lib/components/cart.js +82 -15
  26. package/src/lib/components/cart.js.map +1 -1
  27. package/src/lib/components/checkout-return-notice.d.ts +26 -0
  28. package/src/lib/components/checkout-return-notice.js +48 -0
  29. package/src/lib/components/checkout-return-notice.js.map +1 -0
  30. package/src/lib/components/commerce-console-page.js +124 -0
  31. package/src/lib/components/commerce-console-page.js.map +1 -1
  32. package/src/lib/components/commerce-console-sections.d.ts +1 -1
  33. package/src/lib/components/commerce-console-sections.js +4 -0
  34. package/src/lib/components/commerce-console-sections.js.map +1 -1
  35. package/src/lib/components/console/bulk-fulfill.d.ts +44 -0
  36. package/src/lib/components/console/bulk-fulfill.js +84 -0
  37. package/src/lib/components/console/bulk-fulfill.js.map +1 -0
  38. package/src/lib/components/console/catalog-organization-card.component.js +1 -0
  39. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
  40. package/src/lib/components/console/customer-notifications-card.component.d.ts +19 -0
  41. package/src/lib/components/console/customer-notifications-card.component.js +149 -0
  42. package/src/lib/components/console/customer-notifications-card.component.js.map +1 -0
  43. package/src/lib/components/console/host-orders-card.component.js +88 -6
  44. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  45. package/src/lib/components/console/locations-card.component.js +164 -57
  46. package/src/lib/components/console/locations-card.component.js.map +1 -1
  47. package/src/lib/components/console/order-detail-dialog.component.js +209 -61
  48. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  49. package/src/lib/components/console/order-fulfillment-panel.component.d.ts +48 -0
  50. package/src/lib/components/console/order-fulfillment-panel.component.js +542 -0
  51. package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -0
  52. package/src/lib/components/console/order-invoice.component.d.ts +33 -0
  53. package/src/lib/components/console/order-invoice.component.js +81 -0
  54. package/src/lib/components/console/order-invoice.component.js.map +1 -0
  55. package/src/lib/components/console/order-receipt-resend.component.d.ts +21 -0
  56. package/src/lib/components/console/order-receipt-resend.component.js +203 -0
  57. package/src/lib/components/console/order-receipt-resend.component.js.map +1 -0
  58. package/src/lib/components/console/order-returns.component.d.ts +36 -0
  59. package/src/lib/components/console/order-returns.component.js +142 -0
  60. package/src/lib/components/console/order-returns.component.js.map +1 -0
  61. package/src/lib/components/console/order-shipping-actions.component.d.ts +54 -0
  62. package/src/lib/components/console/order-shipping-actions.component.js +149 -0
  63. package/src/lib/components/console/order-shipping-actions.component.js.map +1 -0
  64. package/src/lib/components/console/order-webhooks-card.component.d.ts +50 -0
  65. package/src/lib/components/console/order-webhooks-card.component.js +623 -0
  66. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -0
  67. package/src/lib/components/console/order-zones.d.ts +155 -0
  68. package/src/lib/components/console/order-zones.js +40 -0
  69. package/src/lib/components/console/order-zones.js.map +1 -0
  70. package/src/lib/components/console/payment-methods-card.component.d.ts +67 -0
  71. package/src/lib/components/console/payment-methods-card.component.js +395 -0
  72. package/src/lib/components/console/payment-methods-card.component.js.map +1 -0
  73. package/src/lib/components/console/pos/pos-api.d.ts +124 -0
  74. package/src/lib/components/console/pos/pos-api.js +101 -0
  75. package/src/lib/components/console/pos/pos-api.js.map +1 -0
  76. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +36 -0
  77. package/src/lib/components/console/pos/pos-cart-panel.component.js +160 -0
  78. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -0
  79. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +39 -0
  80. package/src/lib/components/console/pos/pos-item-dialog.component.js +352 -0
  81. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -0
  82. package/src/lib/components/console/pos/pos-product-grid.component.d.ts +47 -0
  83. package/src/lib/components/console/pos/pos-product-grid.component.js +272 -0
  84. package/src/lib/components/console/pos/pos-product-grid.component.js.map +1 -0
  85. package/src/lib/components/console/pos/pos-receipt-panel.component.d.ts +27 -0
  86. package/src/lib/components/console/pos/pos-receipt-panel.component.js +282 -0
  87. package/src/lib/components/console/pos/pos-receipt-panel.component.js.map +1 -0
  88. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +53 -0
  89. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +445 -0
  90. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -0
  91. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +31 -0
  92. package/src/lib/components/console/pos/pos-tender-panel.component.js +640 -0
  93. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -0
  94. package/src/lib/components/console/pos/use-pos-display.d.ts +43 -0
  95. package/src/lib/components/console/pos/use-pos-display.js +161 -0
  96. package/src/lib/components/console/pos/use-pos-display.js.map +1 -0
  97. package/src/lib/components/console/pos-devices-card.component.d.ts +14 -0
  98. package/src/lib/components/console/pos-devices-card.component.js +546 -0
  99. package/src/lib/components/console/pos-devices-card.component.js.map +1 -0
  100. package/src/lib/components/console/pos-display/brand-screen.d.ts +33 -0
  101. package/src/lib/components/console/pos-display/brand-screen.js +85 -0
  102. package/src/lib/components/console/pos-display/brand-screen.js.map +1 -0
  103. package/src/lib/components/console/pos-display/cart-screen.d.ts +29 -0
  104. package/src/lib/components/console/pos-display/cart-screen.js +166 -0
  105. package/src/lib/components/console/pos-display/cart-screen.js.map +1 -0
  106. package/src/lib/components/console/pos-display/pairing-screen.d.ts +24 -0
  107. package/src/lib/components/console/pos-display/pairing-screen.js +127 -0
  108. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -0
  109. package/src/lib/components/console/pos-display/pos-display-api.d.ts +90 -0
  110. package/src/lib/components/console/pos-display/pos-display-api.js +140 -0
  111. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -0
  112. package/src/lib/components/console/pos-display/receipt-screen.d.ts +35 -0
  113. package/src/lib/components/console/pos-display/receipt-screen.js +200 -0
  114. package/src/lib/components/console/pos-display/receipt-screen.js.map +1 -0
  115. package/src/lib/components/console/pos-display/tip-screen.d.ts +36 -0
  116. package/src/lib/components/console/pos-display/tip-screen.js +211 -0
  117. package/src/lib/components/console/pos-display/tip-screen.js.map +1 -0
  118. package/src/lib/components/console/pos-display-page.component.d.ts +16 -0
  119. package/src/lib/components/console/pos-display-page.component.js +407 -0
  120. package/src/lib/components/console/pos-display-page.component.js.map +1 -0
  121. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +40 -0
  122. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +289 -0
  123. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -0
  124. package/src/lib/components/console/pos-ops/pos-last-receipt.component.d.ts +34 -0
  125. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js +61 -0
  126. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js.map +1 -0
  127. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +38 -0
  128. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +129 -0
  129. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -0
  130. package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +37 -0
  131. package/src/lib/components/console/pos-ops/pos-ops-api.js +60 -0
  132. package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -0
  133. package/src/lib/components/console/pos-ops/pos-pin-pad.component.d.ts +48 -0
  134. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js +220 -0
  135. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js.map +1 -0
  136. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.d.ts +63 -0
  137. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js +186 -0
  138. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js.map +1 -0
  139. package/src/lib/components/console/pos-ops/pos-receipt.d.ts +39 -0
  140. package/src/lib/components/console/pos-ops/pos-receipt.js +182 -0
  141. package/src/lib/components/console/pos-ops/pos-receipt.js.map +1 -0
  142. package/src/lib/components/console/pos-ops/pos-return-dialog.component.d.ts +40 -0
  143. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js +465 -0
  144. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js.map +1 -0
  145. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.d.ts +29 -0
  146. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +253 -0
  147. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -0
  148. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +34 -0
  149. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +494 -0
  150. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -0
  151. package/src/lib/components/console/pos-ops/pos-shift-report.component.d.ts +37 -0
  152. package/src/lib/components/console/pos-ops/pos-shift-report.component.js +102 -0
  153. package/src/lib/components/console/pos-ops/pos-shift-report.component.js.map +1 -0
  154. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.d.ts +30 -0
  155. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js +277 -0
  156. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js.map +1 -0
  157. package/src/lib/components/console/pos-ops/register-ops.d.ts +28 -0
  158. package/src/lib/components/console/pos-ops/register-ops.js +28 -0
  159. package/src/lib/components/console/pos-ops/register-ops.js.map +1 -0
  160. package/src/lib/components/console/pos-ops/use-pos-cashier.d.ts +46 -0
  161. package/src/lib/components/console/pos-ops/use-pos-cashier.js +128 -0
  162. package/src/lib/components/console/pos-ops/use-pos-cashier.js.map +1 -0
  163. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.d.ts +36 -0
  164. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js +64 -0
  165. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js.map +1 -0
  166. package/src/lib/components/console/pos-page.component.d.ts +13 -5
  167. package/src/lib/components/console/pos-page.component.js +756 -654
  168. package/src/lib/components/console/pos-page.component.js.map +1 -1
  169. package/src/lib/components/console/pos-zones.d.ts +23 -0
  170. package/src/lib/components/console/pos-zones.js +31 -0
  171. package/src/lib/components/console/pos-zones.js.map +1 -0
  172. package/src/lib/components/console/product-editor-dialog.component.js +61 -71
  173. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  174. package/src/lib/components/console/product-labels-dialog.component.d.ts +13 -0
  175. package/src/lib/components/console/product-labels-dialog.component.js +197 -0
  176. package/src/lib/components/console/product-labels-dialog.component.js.map +1 -0
  177. package/src/lib/components/console/product-register-fields.component.d.ts +19 -0
  178. package/src/lib/components/console/product-register-fields.component.js +241 -0
  179. package/src/lib/components/console/product-register-fields.component.js.map +1 -0
  180. package/src/lib/components/console/product-zones.d.ts +44 -0
  181. package/src/lib/components/console/product-zones.js.map +1 -1
  182. package/src/lib/components/console/products-hub-card.component.js +23 -20
  183. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  184. package/src/lib/components/console/register-hardware-card.component.d.ts +33 -0
  185. package/src/lib/components/console/register-hardware-card.component.js +826 -0
  186. package/src/lib/components/console/register-hardware-card.component.js.map +1 -0
  187. package/src/lib/components/console/registers-card.component.js +24 -5
  188. package/src/lib/components/console/registers-card.component.js.map +1 -1
  189. package/src/lib/components/console/return-actions.d.ts +38 -0
  190. package/src/lib/components/console/return-actions.js +76 -0
  191. package/src/lib/components/console/return-actions.js.map +1 -0
  192. package/src/lib/components/console/return-detail-dialog.component.d.ts +34 -0
  193. package/src/lib/components/console/return-detail-dialog.component.js +718 -0
  194. package/src/lib/components/console/return-detail-dialog.component.js.map +1 -0
  195. package/src/lib/components/console/return-settings-card.component.d.ts +34 -0
  196. package/src/lib/components/console/return-settings-card.component.js +195 -0
  197. package/src/lib/components/console/return-settings-card.component.js.map +1 -0
  198. package/src/lib/components/console/return-zones.d.ts +87 -0
  199. package/src/lib/components/console/return-zones.js +31 -0
  200. package/src/lib/components/console/return-zones.js.map +1 -0
  201. package/src/lib/components/console/returns-card.component.d.ts +45 -0
  202. package/src/lib/components/console/returns-card.component.js +159 -0
  203. package/src/lib/components/console/returns-card.component.js.map +1 -0
  204. package/src/lib/components/console/shipping-settings-card.component.js +161 -5
  205. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  206. package/src/lib/components/console/shippingeasy-card.component.d.ts +59 -0
  207. package/src/lib/components/console/shippingeasy-card.component.js +378 -0
  208. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -0
  209. package/src/lib/components/console/shipstation-card.component.d.ts +35 -0
  210. package/src/lib/components/console/shipstation-card.component.js +345 -0
  211. package/src/lib/components/console/shipstation-card.component.js.map +1 -0
  212. package/src/lib/components/console/start-return-dialog.component.d.ts +40 -0
  213. package/src/lib/components/console/start-return-dialog.component.js +243 -0
  214. package/src/lib/components/console/start-return-dialog.component.js.map +1 -0
  215. package/src/lib/components/console/stock-movements-card.component.js +2 -1
  216. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  217. package/src/lib/components/console/store-settings-card.component.js +2 -66
  218. package/src/lib/components/console/store-settings-card.component.js.map +1 -1
  219. package/src/lib/components/console/store-zones.d.ts +42 -0
  220. package/src/lib/components/console/store-zones.js +39 -0
  221. package/src/lib/components/console/store-zones.js.map +1 -0
  222. package/src/lib/components/console/storefront-tax-summary-card.component.js +1 -0
  223. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -1
  224. package/src/lib/components/order-status.d.ts +36 -0
  225. package/src/lib/components/order-status.js +502 -0
  226. package/src/lib/components/order-status.js.map +1 -0
  227. package/src/lib/components/product-detail.js +41 -2
  228. package/src/lib/components/product-detail.js.map +1 -1
  229. package/src/lib/components/return-request.d.ts +32 -0
  230. package/src/lib/components/return-request.js +576 -0
  231. package/src/lib/components/return-request.js.map +1 -0
  232. package/src/lib/components/storefront-payment-appearance.d.ts +32 -0
  233. package/src/lib/components/storefront-payment-appearance.js +114 -0
  234. package/src/lib/components/storefront-payment-appearance.js.map +1 -0
  235. package/src/lib/components/storefront-payment-element.d.ts +57 -1
  236. package/src/lib/components/storefront-payment-element.js +332 -33
  237. package/src/lib/components/storefront-payment-element.js.map +1 -1
  238. package/src/lib/constants/order-status.d.ts +22 -0
  239. package/src/lib/constants/order-status.js +22 -0
  240. package/src/lib/constants/order-status.js.map +1 -0
  241. package/src/lib/constants/return-request.d.ts +27 -0
  242. package/src/lib/constants/return-request.js +32 -0
  243. package/src/lib/constants/return-request.js.map +1 -0
  244. package/src/lib/constants/stock-movement-query.js +2 -1
  245. package/src/lib/constants/stock-movement-query.js.map +1 -1
  246. package/src/lib/declarations.console-server.js +9 -0
  247. package/src/lib/declarations.console-server.js.map +1 -1
  248. package/src/lib/declarations.server.d.ts +2 -1
  249. package/src/lib/declarations.server.js +68 -1
  250. package/src/lib/declarations.server.js.map +1 -1
  251. package/src/lib/model/buyer-notifications.d.ts +59 -0
  252. package/src/lib/model/buyer-notifications.js +97 -0
  253. package/src/lib/model/buyer-notifications.js.map +1 -0
  254. package/src/lib/model/commerce-orders.d.ts +171 -2
  255. package/src/lib/model/commerce-orders.js +26 -16
  256. package/src/lib/model/commerce-orders.js.map +1 -1
  257. package/src/lib/model/commerce-payment-methods.d.ts +146 -0
  258. package/src/lib/model/commerce-payment-methods.js +247 -0
  259. package/src/lib/model/commerce-payment-methods.js.map +1 -0
  260. package/src/lib/model/commerce-pos-ops.d.ts +437 -0
  261. package/src/lib/model/commerce-pos-ops.js +721 -0
  262. package/src/lib/model/commerce-pos-ops.js.map +1 -0
  263. package/src/lib/model/commerce-pos.d.ts +263 -0
  264. package/src/lib/model/commerce-pos.js +375 -0
  265. package/src/lib/model/commerce-pos.js.map +1 -0
  266. package/src/lib/model/commerce-printers.d.ts +211 -0
  267. package/src/lib/model/commerce-printers.js +181 -0
  268. package/src/lib/model/commerce-printers.js.map +1 -0
  269. package/src/lib/model/commerce-receipt.d.ts +97 -0
  270. package/src/lib/model/commerce-receipt.js +180 -0
  271. package/src/lib/model/commerce-receipt.js.map +1 -0
  272. package/src/lib/model/commerce-returns.d.ts +207 -0
  273. package/src/lib/model/commerce-returns.js +300 -0
  274. package/src/lib/model/commerce-returns.js.map +1 -0
  275. package/src/lib/model/commerce-shipping.d.ts +44 -1
  276. package/src/lib/model/commerce-shipping.js +53 -9
  277. package/src/lib/model/commerce-shipping.js.map +1 -1
  278. package/src/lib/model/commerce-tax-engine.d.ts +90 -0
  279. package/src/lib/model/commerce-tax-engine.js +129 -0
  280. package/src/lib/model/commerce-tax-engine.js.map +1 -0
  281. package/src/lib/model/commerce.d.ts +91 -2
  282. package/src/lib/model/commerce.js +89 -1
  283. package/src/lib/model/commerce.js.map +1 -1
  284. package/src/lib/model/index.d.ts +16 -0
  285. package/src/lib/model/index.js +16 -0
  286. package/src/lib/model/index.js.map +1 -1
  287. package/src/lib/model/order-events.d.ts +154 -0
  288. package/src/lib/model/order-events.js +153 -0
  289. package/src/lib/model/order-events.js.map +1 -0
  290. package/src/lib/model/order-fulfillment.d.ts +117 -0
  291. package/src/lib/model/order-fulfillment.js +217 -0
  292. package/src/lib/model/order-fulfillment.js.map +1 -0
  293. package/src/lib/model/order-history.d.ts +58 -0
  294. package/src/lib/model/order-history.js +22 -0
  295. package/src/lib/model/order-history.js.map +1 -0
  296. package/src/lib/model/order-list-fields.d.ts +9 -1
  297. package/src/lib/model/order-list-fields.js +7 -1
  298. package/src/lib/model/order-list-fields.js.map +1 -1
  299. package/src/lib/model/order-shipping-export.d.ts +91 -0
  300. package/src/lib/model/order-shipping-export.js +192 -0
  301. package/src/lib/model/order-shipping-export.js.map +1 -0
  302. package/src/lib/model/order-status-view.d.ts +103 -0
  303. package/src/lib/model/order-status-view.js +156 -0
  304. package/src/lib/model/order-status-view.js.map +1 -0
  305. package/src/lib/model/order-webhooks.d.ts +142 -0
  306. package/src/lib/model/order-webhooks.js +91 -0
  307. package/src/lib/model/order-webhooks.js.map +1 -0
  308. package/src/lib/model/product-channel.d.ts +56 -0
  309. package/src/lib/model/product-channel.js +86 -0
  310. package/src/lib/model/product-channel.js.map +1 -0
  311. package/src/lib/model/product-modifiers.d.ts +80 -0
  312. package/src/lib/model/product-modifiers.js +140 -0
  313. package/src/lib/model/product-modifiers.js.map +1 -0
  314. package/src/lib/model/product-write.d.ts +186 -0
  315. package/src/lib/model/product-write.js +116 -0
  316. package/src/lib/model/product-write.js.map +1 -0
  317. package/src/lib/model/shippingeasy.d.ts +94 -0
  318. package/src/lib/model/shippingeasy.js +267 -0
  319. package/src/lib/model/shippingeasy.js.map +1 -0
  320. package/src/lib/model/shipstation.d.ts +125 -0
  321. package/src/lib/model/shipstation.js +399 -0
  322. package/src/lib/model/shipstation.js.map +1 -0
  323. package/src/lib/model/smart-collection-reads.d.ts +32 -0
  324. package/src/lib/model/smart-collection-reads.js +63 -0
  325. package/src/lib/model/smart-collection-reads.js.map +1 -0
  326. package/src/lib/model/tracking-url.d.ts +74 -0
  327. package/src/lib/model/tracking-url.js +159 -0
  328. package/src/lib/model/tracking-url.js.map +1 -0
  329. package/src/lib/plugin-config.d.ts +13 -0
  330. package/src/lib/plugin-config.js +77 -5
  331. package/src/lib/plugin-config.js.map +1 -1
  332. package/src/lib/plugin.js +26 -0
  333. package/src/lib/plugin.js.map +1 -1
  334. package/src/lib/pos-ops-config.d.ts +39 -0
  335. package/src/lib/pos-ops-config.js +88 -0
  336. package/src/lib/pos-ops-config.js.map +1 -0
  337. package/src/lib/printing/print-document.d.ts +106 -0
  338. package/src/lib/printing/print-document.js +464 -0
  339. package/src/lib/printing/print-document.js.map +1 -0
  340. package/src/lib/printing/product-labels.d.ts +58 -0
  341. package/src/lib/printing/product-labels.js +116 -0
  342. package/src/lib/printing/product-labels.js.map +1 -0
  343. package/src/lib/printing/render-epson.d.ts +57 -0
  344. package/src/lib/printing/render-epson.js +135 -0
  345. package/src/lib/printing/render-epson.js.map +1 -0
  346. package/src/lib/printing/render-star.d.ts +45 -0
  347. package/src/lib/printing/render-star.js +100 -0
  348. package/src/lib/printing/render-star.js.map +1 -0
  349. package/src/lib/printing/render-text.d.ts +25 -0
  350. package/src/lib/printing/render-text.js +53 -0
  351. package/src/lib/printing/render-text.js.map +1 -0
  352. package/src/lib/server/api-v1/openapi.js +27 -4
  353. package/src/lib/server/api-v1/openapi.js.map +1 -1
  354. package/src/lib/server/api-v1/order-view.d.ts +67 -0
  355. package/src/lib/server/api-v1/order-view.js +120 -0
  356. package/src/lib/server/api-v1/order-view.js.map +1 -0
  357. package/src/lib/server/api-v1/orders-and-products.js +58 -65
  358. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  359. package/src/lib/server/billing-webhook.js +135 -28
  360. package/src/lib/server/billing-webhook.js.map +1 -1
  361. package/src/lib/server/cancel-order.js +29 -0
  362. package/src/lib/server/cancel-order.js.map +1 -1
  363. package/src/lib/server/carrier-rates-availability.d.ts +26 -0
  364. package/src/lib/server/carrier-rates-availability.js +76 -0
  365. package/src/lib/server/carrier-rates-availability.js.map +1 -0
  366. package/src/lib/server/carrier-shipping.d.ts +84 -0
  367. package/src/lib/server/carrier-shipping.js +135 -0
  368. package/src/lib/server/carrier-shipping.js.map +1 -0
  369. package/src/lib/server/cart-checkout.d.ts +2 -0
  370. package/src/lib/server/cart-checkout.js +226 -22
  371. package/src/lib/server/cart-checkout.js.map +1 -1
  372. package/src/lib/server/channel-order-updates.d.ts +50 -0
  373. package/src/lib/server/channel-order-updates.js +290 -0
  374. package/src/lib/server/channel-order-updates.js.map +1 -0
  375. package/src/lib/server/channel-orders.d.ts +85 -0
  376. package/src/lib/server/channel-orders.js +543 -0
  377. package/src/lib/server/channel-orders.js.map +1 -0
  378. package/src/lib/server/checkout-extras.d.ts +64 -0
  379. package/src/lib/server/checkout-extras.js +157 -0
  380. package/src/lib/server/checkout-extras.js.map +1 -0
  381. package/src/lib/server/{feed.d.ts → checkout-status.d.ts} +2 -7
  382. package/src/lib/server/checkout-status.js +111 -0
  383. package/src/lib/server/checkout-status.js.map +1 -0
  384. package/src/lib/server/checkout.js +86 -9
  385. package/src/lib/server/checkout.js.map +1 -1
  386. package/src/lib/server/draft-order.js +34 -5
  387. package/src/lib/server/draft-order.js.map +1 -1
  388. package/src/lib/server/fulfill-order.d.ts +127 -10
  389. package/src/lib/server/fulfill-order.js +451 -49
  390. package/src/lib/server/fulfill-order.js.map +1 -1
  391. package/src/lib/server/legacy-feed.d.ts +28 -0
  392. package/src/lib/server/legacy-feed.js +52 -0
  393. package/src/lib/server/legacy-feed.js.map +1 -0
  394. package/src/lib/server/native-checkout.d.ts +34 -15
  395. package/src/lib/server/native-checkout.js +32 -17
  396. package/src/lib/server/native-checkout.js.map +1 -1
  397. package/src/lib/server/order-event-host-emit.d.ts +23 -0
  398. package/src/lib/server/order-event-host-emit.js +30 -0
  399. package/src/lib/server/order-event-host-emit.js.map +1 -0
  400. package/src/lib/server/order-event-triggers.d.ts +37 -0
  401. package/src/lib/server/order-event-triggers.js +119 -0
  402. package/src/lib/server/order-event-triggers.js.map +1 -0
  403. package/src/lib/server/order-events.d.ts +62 -0
  404. package/src/lib/server/order-events.js +109 -0
  405. package/src/lib/server/order-events.js.map +1 -0
  406. package/src/lib/server/order-history.d.ts +23 -0
  407. package/src/lib/server/order-history.js +65 -0
  408. package/src/lib/server/order-history.js.map +1 -0
  409. package/src/lib/server/order-notifications.d.ts +185 -0
  410. package/src/lib/server/order-notifications.js +567 -0
  411. package/src/lib/server/order-notifications.js.map +1 -0
  412. package/src/lib/server/order-receipt-send.d.ts +39 -0
  413. package/src/lib/server/order-receipt-send.js +151 -0
  414. package/src/lib/server/order-receipt-send.js.map +1 -0
  415. package/src/lib/server/order-status-token.d.ts +31 -0
  416. package/src/lib/server/order-status-token.js +75 -0
  417. package/src/lib/server/order-status-token.js.map +1 -0
  418. package/src/lib/server/order-status.d.ts +58 -0
  419. package/src/lib/server/order-status.js +141 -0
  420. package/src/lib/server/order-status.js.map +1 -0
  421. package/src/lib/server/order-webhooks.d.ts +108 -0
  422. package/src/lib/server/order-webhooks.js +622 -0
  423. package/src/lib/server/order-webhooks.js.map +1 -0
  424. package/src/lib/server/orders-shipping-prepare.d.ts +26 -0
  425. package/src/lib/server/orders-shipping-prepare.js +121 -0
  426. package/src/lib/server/orders-shipping-prepare.js.map +1 -0
  427. package/src/lib/server/payment-method-domains.d.ts +209 -0
  428. package/src/lib/server/payment-method-domains.js +444 -0
  429. package/src/lib/server/payment-method-domains.js.map +1 -0
  430. package/src/lib/server/payment-methods.d.ts +77 -0
  431. package/src/lib/server/payment-methods.js +284 -0
  432. package/src/lib/server/payment-methods.js.map +1 -0
  433. package/src/lib/server/pos-auth.d.ts +50 -0
  434. package/src/lib/server/pos-auth.js +121 -0
  435. package/src/lib/server/pos-auth.js.map +1 -0
  436. package/src/lib/server/pos-customer.d.ts +49 -0
  437. package/src/lib/server/pos-customer.js +257 -0
  438. package/src/lib/server/pos-customer.js.map +1 -0
  439. package/src/lib/server/pos-display.d.ts +57 -0
  440. package/src/lib/server/pos-display.js +419 -0
  441. package/src/lib/server/pos-display.js.map +1 -0
  442. package/src/lib/server/pos-fee-month.d.ts +34 -0
  443. package/src/lib/server/pos-fee-month.js +36 -0
  444. package/src/lib/server/pos-fee-month.js.map +1 -0
  445. package/src/lib/server/pos-ops-gate.d.ts +161 -0
  446. package/src/lib/server/pos-ops-gate.js +295 -0
  447. package/src/lib/server/pos-ops-gate.js.map +1 -0
  448. package/src/lib/server/pos-ops-routes.d.ts +22 -0
  449. package/src/lib/server/pos-ops-routes.js +36 -0
  450. package/src/lib/server/pos-ops-routes.js.map +1 -0
  451. package/src/lib/server/pos-order.d.ts +1 -18
  452. package/src/lib/server/pos-order.js +222 -42
  453. package/src/lib/server/pos-order.js.map +1 -1
  454. package/src/lib/server/pos-payment.d.ts +39 -0
  455. package/src/lib/server/pos-payment.js +922 -0
  456. package/src/lib/server/pos-payment.js.map +1 -0
  457. package/src/lib/server/pos-print.d.ts +82 -0
  458. package/src/lib/server/pos-print.js +193 -0
  459. package/src/lib/server/pos-print.js.map +1 -0
  460. package/src/lib/server/pos-readers.d.ts +27 -0
  461. package/src/lib/server/pos-readers.js +276 -0
  462. package/src/lib/server/pos-readers.js.map +1 -0
  463. package/src/lib/server/pos-refund-authority.d.ts +60 -0
  464. package/src/lib/server/pos-refund-authority.js +72 -0
  465. package/src/lib/server/pos-refund-authority.js.map +1 -0
  466. package/src/lib/server/pos-return.d.ts +58 -0
  467. package/src/lib/server/pos-return.js +891 -0
  468. package/src/lib/server/pos-return.js.map +1 -0
  469. package/src/lib/server/pos-sale-stamp.d.ts +66 -0
  470. package/src/lib/server/pos-sale-stamp.js +84 -0
  471. package/src/lib/server/pos-sale-stamp.js.map +1 -0
  472. package/src/lib/server/pos-sale.d.ts +170 -0
  473. package/src/lib/server/pos-sale.js +461 -0
  474. package/src/lib/server/pos-sale.js.map +1 -0
  475. package/src/lib/server/pos-shift.d.ts +45 -0
  476. package/src/lib/server/pos-shift.js +484 -0
  477. package/src/lib/server/pos-shift.js.map +1 -0
  478. package/src/lib/server/pos-staff-pin.d.ts +26 -0
  479. package/src/lib/server/pos-staff-pin.js +339 -0
  480. package/src/lib/server/pos-staff-pin.js.map +1 -0
  481. package/src/lib/server/pos-stripe.d.ts +91 -0
  482. package/src/lib/server/pos-stripe.js +129 -0
  483. package/src/lib/server/pos-stripe.js.map +1 -0
  484. package/src/lib/server/pos-terminal-connection-token.d.ts +48 -0
  485. package/src/lib/server/pos-terminal-connection-token.js +166 -0
  486. package/src/lib/server/pos-terminal-connection-token.js.map +1 -0
  487. package/src/lib/server/pos-terminal.d.ts +218 -0
  488. package/src/lib/server/pos-terminal.js +1014 -0
  489. package/src/lib/server/pos-terminal.js.map +1 -0
  490. package/src/lib/server/print-queue.d.ts +124 -0
  491. package/src/lib/server/print-queue.js +301 -0
  492. package/src/lib/server/print-queue.js.map +1 -0
  493. package/src/lib/server/printer-poll.d.ts +75 -0
  494. package/src/lib/server/printer-poll.js +325 -0
  495. package/src/lib/server/printer-poll.js.map +1 -0
  496. package/src/lib/server/printer-secret.d.ts +39 -0
  497. package/src/lib/server/printer-secret.js +56 -0
  498. package/src/lib/server/printer-secret.js.map +1 -0
  499. package/src/lib/server/printers.d.ts +114 -0
  500. package/src/lib/server/printers.js +546 -0
  501. package/src/lib/server/printers.js.map +1 -0
  502. package/src/lib/server/product-catalog.d.ts +42 -0
  503. package/src/lib/server/product-catalog.js +309 -0
  504. package/src/lib/server/product-catalog.js.map +1 -0
  505. package/src/lib/server/product-drafts.d.ts +5 -1
  506. package/src/lib/server/product-drafts.js +3 -3
  507. package/src/lib/server/product-drafts.js.map +1 -1
  508. package/src/lib/server/product-writer.d.ts +19 -0
  509. package/src/lib/server/product-writer.js +261 -0
  510. package/src/lib/server/product-writer.js.map +1 -0
  511. package/src/lib/server/products-write.d.ts +61 -0
  512. package/src/lib/server/products-write.js +375 -0
  513. package/src/lib/server/products-write.js.map +1 -0
  514. package/src/lib/server/refund.js +110 -45
  515. package/src/lib/server/refund.js.map +1 -1
  516. package/src/lib/server/reserve.js +2 -0
  517. package/src/lib/server/reserve.js.map +1 -1
  518. package/src/lib/server/return-status-action.d.ts +37 -0
  519. package/src/lib/server/return-status-action.js +57 -0
  520. package/src/lib/server/return-status-action.js.map +1 -0
  521. package/src/lib/server/returns.d.ts +119 -0
  522. package/src/lib/server/returns.js +938 -0
  523. package/src/lib/server/returns.js.map +1 -0
  524. package/src/lib/server/shipment-records.d.ts +36 -0
  525. package/src/lib/server/shipment-records.js +289 -0
  526. package/src/lib/server/shipment-records.js.map +1 -0
  527. package/src/lib/server/shipping-connector-gates.d.ts +40 -0
  528. package/src/lib/server/shipping-connector-gates.js +97 -0
  529. package/src/lib/server/shipping-connector-gates.js.map +1 -0
  530. package/src/lib/server/shipping-connectors.d.ts +29 -0
  531. package/src/lib/server/shipping-connectors.js +236 -0
  532. package/src/lib/server/shipping-connectors.js.map +1 -0
  533. package/src/lib/server/shippingeasy.d.ts +238 -0
  534. package/src/lib/server/shippingeasy.js +787 -0
  535. package/src/lib/server/shippingeasy.js.map +1 -0
  536. package/src/lib/server/shipstation.d.ts +129 -0
  537. package/src/lib/server/shipstation.js +483 -0
  538. package/src/lib/server/shipstation.js.map +1 -0
  539. package/src/lib/server/site-page-resolver.d.ts +5 -0
  540. package/src/lib/server/site-page-resolver.js +156 -1
  541. package/src/lib/server/site-page-resolver.js.map +1 -1
  542. package/src/lib/server/stock-levels.d.ts +21 -0
  543. package/src/lib/server/stock-levels.js +263 -0
  544. package/src/lib/server/stock-levels.js.map +1 -0
  545. package/src/lib/server/stripe-refund.d.ts +47 -0
  546. package/src/lib/server/stripe-refund.js +87 -0
  547. package/src/lib/server/stripe-refund.js.map +1 -0
  548. package/src/lib/server/supplier-update.js +46 -5
  549. package/src/lib/server/supplier-update.js.map +1 -1
  550. package/src/lib/server/tax-engine-quote.d.ts +47 -0
  551. package/src/lib/server/tax-engine-quote.js +105 -0
  552. package/src/lib/server/tax-engine-quote.js.map +1 -0
  553. package/src/lib/server.js +143 -2
  554. package/src/lib/server.js.map +1 -1
  555. package/src/lib/site.js +12 -0
  556. package/src/lib/site.js.map +1 -1
  557. package/src/lib/subprocessors.d.ts +26 -0
  558. package/src/lib/subprocessors.js +50 -0
  559. package/src/lib/subprocessors.js.map +1 -0
  560. package/src/lib/tenant-emails.js +461 -3
  561. package/src/lib/tenant-emails.js.map +1 -1
  562. package/src/lib/testing/fake-firestore.d.ts +45 -0
  563. package/src/lib/testing/fake-firestore.js +189 -0
  564. package/src/lib/testing/fake-firestore.js.map +1 -0
  565. package/src/lib/testing/memory-firestore.d.ts +136 -0
  566. package/src/lib/testing/memory-firestore.js +282 -0
  567. package/src/lib/testing/memory-firestore.js.map +1 -0
  568. package/src/lib/testing/pos-ops-harness.d.ts +50 -0
  569. package/src/lib/testing/pos-ops-harness.js +184 -0
  570. package/src/lib/testing/pos-ops-harness.js.map +1 -0
  571. package/src/lib/testing/pos-ops-memory-firestore.d.ts +55 -0
  572. package/src/lib/testing/pos-ops-memory-firestore.js +376 -0
  573. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -0
  574. package/src/lib/transfer/products.server.d.ts +5 -0
  575. package/src/lib/transfer/products.server.js +2 -2
  576. package/src/lib/transfer/products.server.js.map +1 -1
  577. package/src/lib/transfer/records-transfer.d.ts +11 -1
  578. package/src/lib/transfer/records-transfer.js +127 -5
  579. package/src/lib/transfer/records-transfer.js.map +1 -1
  580. package/src/lib/transfer/records.server.d.ts +9 -2
  581. package/src/lib/transfer/records.server.js +58 -7
  582. package/src/lib/transfer/records.server.js.map +1 -1
  583. package/src/lib/transfer/register-transfer-resources.js +40 -1
  584. package/src/lib/transfer/register-transfer-resources.js.map +1 -1
  585. package/src/lib/transfer/register-transfer-ui.js +4 -1
  586. package/src/lib/transfer/register-transfer-ui.js.map +1 -1
  587. package/src/lib/transfer/shipping-presets.d.ts +23 -0
  588. package/src/lib/transfer/shipping-presets.js +156 -0
  589. package/src/lib/transfer/shipping-presets.js.map +1 -0
  590. package/src/lib/transfer/tracking-transfer.d.ts +101 -0
  591. package/src/lib/transfer/tracking-transfer.js +546 -0
  592. package/src/lib/transfer/tracking-transfer.js.map +1 -0
  593. package/src/lib/transfer/tracking.server.d.ts +37 -0
  594. package/src/lib/transfer/tracking.server.js +393 -0
  595. package/src/lib/transfer/tracking.server.js.map +1 -0
  596. package/src/lib/transfer/transfer-keys.d.ts +2 -1
  597. package/src/lib/transfer/transfer-keys.js +6 -2
  598. package/src/lib/transfer/transfer-keys.js.map +1 -1
  599. package/src/lib/utils/code128.d.ts +37 -0
  600. package/src/lib/utils/code128.js +199 -0
  601. package/src/lib/utils/code128.js.map +1 -0
  602. package/src/lib/utils/order-invoice.d.ts +55 -0
  603. package/src/lib/utils/order-invoice.js +127 -0
  604. package/src/lib/utils/order-invoice.js.map +1 -0
  605. package/src/lib/utils/use-checkout-return-notice.d.ts +34 -0
  606. package/src/lib/utils/use-checkout-return-notice.js +78 -0
  607. package/src/lib/utils/use-checkout-return-notice.js.map +1 -0
  608. package/src/lib/server/feed.js +0 -69
  609. package/src/lib/server/feed.js.map +0 -1
@@ -0,0 +1,47 @@
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
+ /**
18
+ * ONE STRIPE REFUND, the way every commerce refund sends one (AGL-3609).
19
+ *
20
+ * Shared by the order dialog's refund (`refund.ts`) and a return at the
21
+ * register (`pos-return.ts`), so both take the money back the same way:
22
+ *
23
+ * - `reverse_transfer`: a destination charge's money sits in the
24
+ * merchant's connected account, so the refund pulls it back from there
25
+ * rather than out of the platform's balance.
26
+ * - `refund_application_fee`: the platform hands its fee back on the
27
+ * refunded share, as it always has.
28
+ * - the caller's IDEMPOTENCY KEY, so a retried request is the same refund
29
+ * at Stripe and never a second one.
30
+ */
31
+ export type StripeRefundResult = {
32
+ ok: true;
33
+ refundId: string;
34
+ } | {
35
+ ok: false;
36
+ status: number;
37
+ error: string;
38
+ code: string;
39
+ };
40
+ export declare function createStripeRefund(input: {
41
+ paymentIntentId: string;
42
+ amountCents: number;
43
+ idempotencyKey?: string | null;
44
+ metadata?: Record<string, string>;
45
+ fetch?: typeof fetch;
46
+ secretKey?: string;
47
+ }): Promise<StripeRefundResult>;
@@ -0,0 +1,87 @@
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
+ * ONE STRIPE REFUND, the way every commerce refund sends one (AGL-3609).
18
+ *
19
+ * Shared by the order dialog's refund (`refund.ts`) and a return at the
20
+ * register (`pos-return.ts`), so both take the money back the same way:
21
+ *
22
+ * - `reverse_transfer`: a destination charge's money sits in the
23
+ * merchant's connected account, so the refund pulls it back from there
24
+ * rather than out of the platform's balance.
25
+ * - `refund_application_fee`: the platform hands its fee back on the
26
+ * refunded share, as it always has.
27
+ * - the caller's IDEMPOTENCY KEY, so a retried request is the same refund
28
+ * at Stripe and never a second one.
29
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
30
+ export async function createStripeRefund(input) {
31
+ var _input_secretKey, _input_metadata, _input_fetch, _ref;
32
+ const secretKey = (_input_secretKey = input.secretKey) != null ? _input_secretKey : process.env.STRIPE_SECRET_KEY;
33
+ if (!secretKey) {
34
+ return {
35
+ ok: false,
36
+ status: 501,
37
+ error: 'Payments are not configured.',
38
+ code: 'not_configured'
39
+ };
40
+ }
41
+ const params = new URLSearchParams({
42
+ payment_intent: input.paymentIntentId,
43
+ amount: String(Math.round(input.amountCents)),
44
+ reverse_transfer: 'true',
45
+ refund_application_fee: 'true'
46
+ });
47
+ for (const [key, value] of Object.entries((_input_metadata = input.metadata) != null ? _input_metadata : {})){
48
+ params.set(`metadata[${key}]`, value);
49
+ }
50
+ const send = (_input_fetch = input.fetch) != null ? _input_fetch : fetch;
51
+ const response = await send('https://api.stripe.com/v1/refunds', {
52
+ method: 'POST',
53
+ headers: _extends({
54
+ Authorization: `Bearer ${secretKey}`,
55
+ 'Content-Type': 'application/x-www-form-urlencoded'
56
+ }, input.idempotencyKey ? {
57
+ 'Idempotency-Key': input.idempotencyKey
58
+ } : {}),
59
+ body: params.toString()
60
+ });
61
+ const refund = await Promise.resolve().then(()=>response.json()).catch(()=>({}));
62
+ if (!response.ok) {
63
+ var _ref1, _ref2;
64
+ var _refund_error, _refund_error1;
65
+ const code = String((_ref1 = refund == null ? void 0 : (_refund_error = refund.error) == null ? void 0 : _refund_error.code) != null ? _ref1 : '');
66
+ if (code === 'charge_disputed' || code === 'refund_disputed_payment') {
67
+ return {
68
+ ok: false,
69
+ status: 409,
70
+ code,
71
+ error: 'Stripe refused this refund because the charge is disputed. ' + 'Respond to the dispute or accept it in the Stripe dashboard; ' + 'refund any remainder once it settles.'
72
+ };
73
+ }
74
+ return {
75
+ ok: false,
76
+ status: 502,
77
+ code,
78
+ error: (_ref2 = refund == null ? void 0 : (_refund_error1 = refund.error) == null ? void 0 : _refund_error1.message) != null ? _ref2 : 'Refund failed'
79
+ };
80
+ }
81
+ return {
82
+ ok: true,
83
+ refundId: String((_ref = refund == null ? void 0 : refund.id) != null ? _ref : '')
84
+ };
85
+ }
86
+
87
+ //# sourceMappingURL=stripe-refund.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/stripe-refund.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\n/**\n * ONE STRIPE REFUND, the way every commerce refund sends one (AGL-3609).\n *\n * Shared by the order dialog's refund (`refund.ts`) and a return at the\n * register (`pos-return.ts`), so both take the money back the same way:\n *\n * - `reverse_transfer`: a destination charge's money sits in the\n * merchant's connected account, so the refund pulls it back from there\n * rather than out of the platform's balance.\n * - `refund_application_fee`: the platform hands its fee back on the\n * refunded share, as it always has.\n * - the caller's IDEMPOTENCY KEY, so a retried request is the same refund\n * at Stripe and never a second one.\n */\nexport type StripeRefundResult =\n | { ok: true; refundId: string }\n | { ok: false; status: number; error: string; code: string }\n\nexport async function createStripeRefund(input: {\n paymentIntentId: string\n amountCents: number\n idempotencyKey?: string | null\n metadata?: Record<string, string>\n fetch?: typeof fetch\n secretKey?: string\n}): Promise<StripeRefundResult> {\n const secretKey = input.secretKey ?? process.env.STRIPE_SECRET_KEY\n if (!secretKey) {\n return { ok: false, status: 501, error: 'Payments are not configured.', code: 'not_configured' }\n }\n const params = new URLSearchParams({\n payment_intent: input.paymentIntentId,\n amount: String(Math.round(input.amountCents)),\n reverse_transfer: 'true',\n refund_application_fee: 'true',\n })\n for (const [key, value] of Object.entries(input.metadata ?? {})) {\n params.set(`metadata[${key}]`, value)\n }\n const send = input.fetch ?? fetch\n const response = await send('https://api.stripe.com/v1/refunds', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${secretKey}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n ...(input.idempotencyKey ? { 'Idempotency-Key': input.idempotencyKey } : {}),\n },\n body: params.toString(),\n })\n const refund = (await Promise.resolve()\n .then(() => response.json())\n .catch(() => ({}))) as {\n id?: string\n error?: { code?: string; message?: string }\n }\n if (!response.ok) {\n const code = String(refund?.error?.code ?? '')\n if (code === 'charge_disputed' || code === 'refund_disputed_payment') {\n return {\n ok: false,\n status: 409,\n code,\n error:\n 'Stripe refused this refund because the charge is disputed. ' +\n 'Respond to the dispute or accept it in the Stripe dashboard; ' +\n 'refund any remainder once it settles.',\n }\n }\n return { ok: false, status: 502, code, error: refund?.error?.message ?? 'Refund failed' }\n }\n return { ok: true, refundId: String(refund?.id ?? '') }\n}\n"],"names":["createStripeRefund","input","secretKey","process","env","STRIPE_SECRET_KEY","ok","status","error","code","params","URLSearchParams","payment_intent","paymentIntentId","amount","String","Math","round","amountCents","reverse_transfer","refund_application_fee","key","value","Object","entries","metadata","set","send","fetch","response","method","headers","Authorization","idempotencyKey","body","toString","refund","Promise","resolve","then","json","catch","message","refundId","id"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;CAaC;AAKD,OAAO,eAAeA,mBAAmBC,KAOxC;QACmBA,kBAUwBA,iBAG7BA;IAbb,MAAMC,aAAYD,mBAAAA,MAAMC,SAAS,YAAfD,mBAAmBE,QAAQC,GAAG,CAACC,iBAAiB;IAClE,IAAI,CAACH,WAAW;QACd,OAAO;YAAEI,IAAI;YAAOC,QAAQ;YAAKC,OAAO;YAAgCC,MAAM;QAAiB;IACjG;IACA,MAAMC,SAAS,IAAIC,gBAAgB;QACjCC,gBAAgBX,MAAMY,eAAe;QACrCC,QAAQC,OAAOC,KAAKC,KAAK,CAAChB,MAAMiB,WAAW;QAC3CC,kBAAkB;QAClBC,wBAAwB;IAC1B;IACA,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,EAACvB,kBAAAA,MAAMwB,QAAQ,YAAdxB,kBAAkB,CAAC,GAAI;QAC/DS,OAAOgB,GAAG,CAAC,CAAC,SAAS,EAAEL,IAAI,CAAC,CAAC,EAAEC;IACjC;IACA,MAAMK,QAAO1B,eAAAA,MAAM2B,KAAK,YAAX3B,eAAe2B;IAC5B,MAAMC,WAAW,MAAMF,KAAK,qCAAqC;QAC/DG,QAAQ;QACRC,SAAS;YACPC,eAAe,CAAC,OAAO,EAAE9B,WAAW;YACpC,gBAAgB;WACZD,MAAMgC,cAAc,GAAG;YAAE,mBAAmBhC,MAAMgC,cAAc;QAAC,IAAI,CAAC;QAE5EC,MAAMxB,OAAOyB,QAAQ;IACvB;IACA,MAAMC,SAAU,MAAMC,QAAQC,OAAO,GAClCC,IAAI,CAAC,IAAMV,SAASW,IAAI,IACxBC,KAAK,CAAC,IAAO,CAAA,CAAC,CAAA;IAIjB,IAAI,CAACZ,SAASvB,EAAE,EAAE;;YACI8B,eAY0BA;QAZ9C,MAAM3B,OAAOM,gBAAOqB,2BAAAA,gBAAAA,OAAQ5B,KAAK,qBAAb4B,cAAe3B,IAAI,oBAAI;QAC3C,IAAIA,SAAS,qBAAqBA,SAAS,2BAA2B;YACpE,OAAO;gBACLH,IAAI;gBACJC,QAAQ;gBACRE;gBACAD,OACE,gEACA,kEACA;YACJ;QACF;QACA,OAAO;YAAEF,IAAI;YAAOC,QAAQ;YAAKE;YAAMD,KAAK,WAAE4B,2BAAAA,iBAAAA,OAAQ5B,KAAK,qBAAb4B,eAAeM,OAAO,oBAAI;QAAgB;IAC1F;IACA,OAAO;QAAEpC,IAAI;QAAMqC,UAAU5B,eAAOqB,0BAAAA,OAAQQ,EAAE,mBAAI;IAAI;AACxD"}
@@ -19,6 +19,9 @@ import { firebaseAdmin, notifyHostManagers } from "@aglyn/tenant-data-admin";
19
19
  import { escapeHtml } from "../utils/escape-html.js";
20
20
  import { createHmac, timingSafeEqual } from "crypto";
21
21
  import { tokenSigningSecret } from "./download.js";
22
+ import { notifyOrderBuyer } from "./order-notifications.js";
23
+ import { ORDER_FULFILLED_EVENT } from "../model/order-events.js";
24
+ import { fulfillmentEventView, stageOrderEvent } from "./order-events.js";
22
25
  /**
23
26
  * Constant-time compare for the per-order supplier token (AGL-2268).
24
27
  *
@@ -232,10 +235,29 @@ import { tokenSigningSecret } from "./download.js";
232
235
  }
233
236
  };
234
237
  }
238
+ // The units still open on the supplier's lines (AGL-3611): the
239
+ // merchant may already have shipped part of one from the console.
240
+ const remainingByLine = new Map(CommerceModel.orderLineFulfillmentStates(order).map((state)=>[
241
+ state.lineItemId,
242
+ state.remainingQuantity
243
+ ]));
244
+ const shippedLines = myLines.map((index)=>{
245
+ var _remainingByLine_get;
246
+ return {
247
+ lineItemId: index,
248
+ quantity: (_remainingByLine_get = remainingByLine.get(index)) != null ? _remainingByLine_get : 0
249
+ };
250
+ }).filter((entry)=>entry.quantity > 0);
235
251
  const fulfillment = _extends({
236
252
  id: `supplier-${Date.now().toString(36)}`,
237
- lineItemIds: myLines
238
- }, carrier ? {
253
+ lineItemIds: shippedLines.map((entry)=>entry.lineItemId),
254
+ lines: shippedLines
255
+ }, carrier && trackingNumber ? (()=>{
256
+ const trackingUrl = CommerceModel.trackingUrlFor(carrier, trackingNumber);
257
+ return trackingUrl ? {
258
+ trackingUrl
259
+ } : {};
260
+ })() : {}, carrier ? {
239
261
  carrier
240
262
  } : {}, trackingNumber ? {
241
263
  trackingNumber
@@ -243,16 +265,27 @@ import { tokenSigningSecret } from "./download.js";
243
265
  atMs: Date.now()
244
266
  });
245
267
  const remaining = ((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).filter((_line, index)=>!coveredAfter.has(index)).length;
246
- transaction.set(orderRef, {
268
+ const shipped = {
247
269
  status: nextStatus,
248
270
  fulfillments: [
249
271
  ...(_order_fulfillments = order.fulfillments) != null ? _order_fulfillments : [],
250
272
  fulfillment
251
273
  ],
274
+ updatedAtMs: Date.now(),
252
275
  timeline: CommerceModel.appendOrderEvent(order, nextStatus, `Supplier shipped ${myLines.length} of ${((_order_lineItems1 = order.lineItems) != null ? _order_lineItems1 : []).length} line${((_order_lineItems2 = order.lineItems) != null ? _order_lineItems2 : []).length === 1 ? '' : 's'}` + (trackingNumber ? ` — ${carrier || 'tracking'} ${trackingNumber}` : '') + (remaining > 0 ? `. ${remaining} line${remaining === 1 ? '' : 's'} still to ship.` : ''))
253
- }, {
276
+ };
277
+ transaction.set(orderRef, shipped, {
254
278
  merge: true
255
279
  });
280
+ stageOrderEvent(transaction, ORDER_FULFILLED_EVENT, {
281
+ hostId,
282
+ orderId,
283
+ key: fulfillment.id,
284
+ order: _extends({}, orderSnapshot.data(), shipped),
285
+ extra: {
286
+ fulfillment: fulfillmentEventView(order, fulfillment)
287
+ }
288
+ });
256
289
  return {
257
290
  status: 200,
258
291
  body: {
@@ -263,7 +296,8 @@ import { tokenSigningSecret } from "./download.js";
263
296
  order,
264
297
  nextStatus,
265
298
  remaining,
266
- supplierId: postingSupplier
299
+ supplierId: postingSupplier,
300
+ fulfillmentId: fulfillment.id
267
301
  };
268
302
  });
269
303
  if (outcome.status !== 200) {
@@ -287,6 +321,13 @@ import { tokenSigningSecret } from "./download.js";
287
321
  ].filter(Boolean).join(' ')}.` : ' No tracking number was given.') + (outstanding > 0 ? ` ${outstanding} line${outstanding === 1 ? ' is' : 's are'} still to ship.` : ''),
288
322
  link: `/${hostId}/products`
289
323
  });
324
+ // …and the buyer hears their parcel is on its way (AGL-3610).
325
+ await notifyOrderBuyer({
326
+ hostId,
327
+ orderId
328
+ }, 'shipped', {
329
+ fulfillmentId: outcome.fulfillmentId
330
+ });
290
331
  return res.status(200).json(outcome.body);
291
332
  } catch (error) {
292
333
  console.error(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/supplier-update.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 * as Aglyn from '@aglyn/aglyn/server'\nimport * as CommerceModel from '../model'\nimport { firebaseAdmin, notifyHostManagers } from '@aglyn/tenant-data-admin'\nimport { escapeHtml } from '../utils/escape-html'\nimport { createHmac, timingSafeEqual } from 'crypto'\nimport { tokenSigningSecret } from './download'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\n\n/**\n * Constant-time compare for the per-order supplier token (AGL-2268).\n *\n * `!==` on a secret leaks its prefix through response timing, and this token is\n * a bearer credential for a route with no account behind it — the only thing\n * standing between the open internet and marking a merchant's order shipped.\n * `download.ts` has compared its own token this way since it shipped; this is\n * the sibling that did not.\n *\n * Length is compared first and OUTSIDE the constant-time call, because\n * `timingSafeEqual` throws on a length mismatch. That leaks the token's LENGTH\n * and nothing else, which is the same concession `download.ts` makes.\n */\nfunction tokenMatches(stored: unknown, presented: string): boolean {\n const expected = typeof stored === 'string' ? stored : ''\n if (!expected || !presented) return false\n const a = Buffer.from(presented)\n const b = Buffer.from(expected)\n if (a.length !== b.length) return false\n return timingSafeEqual(new Uint8Array(a), new Uint8Array(b))\n}\n\n/**\n * WHICH supplier is posting (AGL-2455), and the observation that makes the\n * issue's \"structural blocker\" not structural after all.\n *\n * The order document holds ONE `supplierToken` field, so the issue's reading\n * was that scoping lines per supplier would strand every other supplier's lines\n * permanently: only the last token written could authenticate, and the others\n * would have no valid credential at all. That reading is right about the stored\n * field and wrong about the token.\n *\n * The token is not a random secret that has to be stored to be known. It is\n * `HMAC(hostId:orderId:supplierId)` under `TOKEN_SIGNING_SECRET`\n * (`billing-webhook.ts`), a pure function of three identifiers the order\n * already carries — `supplierId` is stamped onto every line at purchase time.\n * So the expected token for EVERY supplier on the order can be re-derived here\n * and compared, which both identifies the poster and lets every supplier\n * authenticate. No schema change, no migration, no map.\n *\n * Every candidate is compared even after a match, so the work done is a\n * function of the order's supplier count and not of which supplier posted.\n *\n * Returns `null` when nothing matches; the stored-scalar fallback is the\n * caller's, because only it knows whether that fallback is ambiguous.\n */\nfunction resolvePostingSupplier(\n hostId: string,\n orderId: string,\n order: CommerceModel.HostOrder,\n presented: string,\n): string | null {\n let secret: string\n try {\n secret = tokenSigningSecret()\n } catch {\n // Unset secret: no token could have been MINTED either, so there is nothing\n // to derive. Fall through to the stored scalar rather than throwing a 500\n // at a supplier who cannot do anything about it.\n return null\n }\n let matched: string | null = null\n for (const supplierId of CommerceModel.orderSupplierIds(order)) {\n const expected = createHmac('sha256', secret)\n .update(`${hostId}:${orderId}:${supplierId}`)\n .digest('hex')\n .slice(0, 32)\n if (tokenMatches(expected, presented)) matched = supplierId\n }\n return matched\n}\n\n\n/**\n * Supplier tracking callback (AGL-289): the routed order carried a\n * per-order token; posting (or GET-ing, for email links) tracking with\n * it fulfills the order. Token-gated — suppliers have no Aglyn account.\n */\nexport const supplierUpdateHandler: PluginApiHandler = async (req, res) => {\n const source = req.method === 'POST' ? { ...req.query, ...(typeof req.body === 'string' ? JSON.parse(req.body || '{}') : (req.body ?? {})) } : req.query\n const hostId = String(source.hostId ?? '')\n const orderId = String(source.orderId ?? '')\n const token = String(source.token ?? '')\n const trackingNumber = String(source.trackingNumber ?? '').slice(0, 60)\n const carrier = String(source.carrier ?? '').slice(0, 40)\n if (!hostId || !orderId || !token) {\n return res.status(400).json({ error: 'Missing hostId, orderId, or token' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which fell into the catch below and answered 500 to what is a 400\n // (AGL-2455). `fulfill-order.ts` has had this guard since it shipped; this is\n // the sibling route that did not.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId, orderId, or token' })\n }\n\n try {\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = firestore\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n // A GET NEVER MOVES THE ORDER (AGL-2268). The supplier email carries this\n // URL, and a GET that fulfils means every link scanner, spam filter,\n // preview generator and browser prefetch on the path between us and the\n // supplier's inbox marks the order shipped — before anything shipped, and\n // with no tracking number on it. The link still works and the email is\n // unchanged: a GET renders a one-button page that POSTs the same\n // parameters, so the supplier's experience is one extra click and the\n // machines that open mail for a living take no action at all.\n if (req.method === 'GET') {\n res.setHeader('Content-Type', 'text/html')\n const field = (name: string, value: string) =>\n `<input type=\"hidden\" name=\"${name}\" value=\"${escapeHtml(value)}\">`\n // The carrier and the number are FIELDS the supplier fills in\n // (AGL-3432), so the emailed link needs no placeholders for them to\n // edit in the URL. A value a link does carry arrives filled in.\n const input = (name: string, label: string, value: string) =>\n `<p><label>${label}<br>` +\n `<input type=\"text\" name=\"${name}\" value=\"${escapeHtml(value)}\"></label></p>`\n return res.status(200).send(\n '<h3>Record this shipment</h3>' +\n '<p>Enter the carrier and tracking number, then press the button ' +\n 'to record it against the order.</p>' +\n '<form method=\"POST\">' +\n field('hostId', hostId) +\n field('orderId', orderId) +\n field('token', token) +\n input('carrier', 'Carrier', carrier) +\n input('trackingNumber', 'Tracking number', trackingNumber) +\n '<button type=\"submit\">Mark as shipped</button>' +\n '</form>',\n )\n }\n\n // THE READ, THE TRANSITION CHECK AND THE WRITE ARE ONE ACT (AGL-2268).\n // They used to be a plain `get()`, a check, and a `set(…, {merge:true})`,\n // which is the exact stale-read hole AGL-1808/1818/1819 closed on the\n // console's own fulfil, cancel and refund routes — reopened here, on the\n // one door with no account behind it. A supplier POST racing a refund read\n // `paid`, the refund landed, and the POST then wrote `fulfilled` over\n // `refunded`. `ORDER_TRANSITIONS` says `refunded: []`, and the cost is not\n // cosmetic: `gate.ts`, `download.ts`, `membership-account.ts` and\n // `reviews.ts` all withdraw a shopper's entitlement by matching that\n // literal, so the refunded buyer got their downloads back.\n const outcome = await firebaseAdmin\n .app()\n .firestore()\n .runTransaction(async (transaction) => {\n const orderSnapshot = await transaction.get(orderRef)\n if (!orderSnapshot.exists) {\n return { status: 404, body: { error: 'Unknown order' } as any }\n }\n const order = CommerceModel.liftLegacyOrder(orderSnapshot.data() as any)\n // ONE SUPPLIER SHIPS ONE SUPPLIER'S LINES (AGL-2455).\n //\n // `lineItemIds` used to be every index on the order and the status was\n // written as the literal `'fulfilled'`, so the first supplier to post\n // marked the whole order shipped — lines they had never seen included —\n // and the second supplier's POST met a 409. The buyer was told\n // everything shipped with one carrier and one tracking number.\n const suppliers = CommerceModel.orderSupplierIds(order)\n const postingSupplier = resolvePostingSupplier(\n hostId,\n orderId,\n order,\n token,\n )\n let myLines: number[]\n if (postingSupplier) {\n myLines = CommerceModel.supplierLineItemIds(order, postingSupplier)\n } else if (tokenMatches(orderSnapshot.get('supplierToken'), token)) {\n // The STORED scalar matched but no supplier on the order derives to\n // it — an order whose lines carry no `supplierId`, which is every\n // order routed before that field was stamped.\n //\n // With at most one supplier there is only one door, so claiming every\n // line is the same answer this route has always given and is right.\n // With TWO OR MORE, the scalar cannot say whose token it is, and\n // guessing would either close lines a supplier never shipped (the\n // defect) or strand them (the naive fix). REFUSED LOUDLY instead:\n // the merchant fulfils from the console, where they can see the\n // lines, and the message says so rather than leaving them to work it\n // out from an order that silently went quiet.\n if (suppliers.length > 1) {\n return {\n status: 409,\n body: {\n error:\n 'This order has more than one supplier and the link cannot ' +\n 'say which of them you are. Nothing was changed. Please ask ' +\n 'the merchant to record this shipment from their console.',\n } as any,\n }\n }\n myLines = (order.lineItems ?? []).map((_line, index) => index)\n } else {\n return { status: 403, body: { error: 'Invalid token' } as any }\n }\n if (myLines.length === 0) {\n return {\n status: 409,\n body: { error: 'No lines on this order are yours' } as any,\n }\n }\n const coveredBefore = CommerceModel.coveredLineItemIds(order)\n if (myLines.every((index) => coveredBefore.has(index))) {\n // Every line of theirs is already shipped: a redelivered POST, or the\n // supplier pressing the emailed button twice. Refused rather than\n // appending a second copy of the same fulfillment — the same rule\n // `fulfill-order.ts` applies to a retried click.\n return {\n status: 409,\n body: {\n error:\n suppliers.length > 1\n ? 'Your lines on this order are already marked shipped'\n : `Order is already ${order.status}`,\n } as any,\n }\n }\n const coveredAfter = new Set([...coveredBefore, ...myLines])\n // COMPUTED, not written as a literal. `partially_fulfilled` has been in\n // `ORDER_TRANSITIONS` since orders shipped and nothing ever wrote it.\n const nextStatus = CommerceModel.statusAfterFulfilling(\n order,\n coveredAfter,\n )\n // Re-asked inside the transaction that writes, as AGL-2268 established:\n // a supplier POST racing a refund must not write over `refunded`. Only\n // when the status actually MOVES — a second supplier posting onto an\n // already `partially_fulfilled` order changes nothing about the status\n // and must not be refused by a table that has no self-edge.\n if (\n nextStatus !== order.status &&\n !CommerceModel.canTransitionOrder(order.status, nextStatus)\n ) {\n return {\n status: 409,\n body: { error: `Order is already ${order.status}` } as any,\n }\n }\n const fulfillment: CommerceModel.OrderFulfillment = {\n id: `supplier-${Date.now().toString(36)}`,\n lineItemIds: myLines,\n ...(carrier ? { carrier } : {}),\n ...(trackingNumber ? { trackingNumber } : {}),\n atMs: Date.now(),\n }\n const remaining = (order.lineItems ?? []).filter(\n (_line, index) => !coveredAfter.has(index),\n ).length\n transaction.set(\n orderRef,\n {\n status: nextStatus,\n fulfillments: [...(order.fulfillments ?? []), fulfillment],\n timeline: CommerceModel.appendOrderEvent(\n order,\n nextStatus,\n `Supplier shipped ${myLines.length} of ${\n (order.lineItems ?? []).length\n } line${(order.lineItems ?? []).length === 1 ? '' : 's'}` +\n (trackingNumber\n ? ` — ${carrier || 'tracking'} ${trackingNumber}`\n : '') +\n (remaining > 0\n ? `. ${remaining} line${remaining === 1 ? '' : 's'} still to ship.`\n : ''),\n ),\n },\n { merge: true },\n )\n return {\n status: 200,\n body: { ok: true, lineItemIds: myLines, orderStatus: nextStatus } as any,\n order,\n nextStatus,\n remaining,\n supplierId: postingSupplier,\n }\n })\n if (outcome.status !== 200) {\n return res.status(outcome.status).json(outcome.body)\n }\n // The merchant is told what is STILL OUTSTANDING (AGL-2455). \"Supplier\n // shipped #1042\" on an order where one of three suppliers has posted reads\n // as done, which is the same misreport the status literal made — the\n // merchant would stop watching an order that is two thirds unshipped.\n const outstanding = Number((outcome as any).remaining ?? 0)\n const orderLabel = CommerceModel.formatOrderNumber(\n outcome.order as CommerceModel.HostOrder,\n orderId,\n )\n // Which supplier, which order, where, and the tracking (AGL-3432).\n const supplierId = (outcome as any).supplierId as string | null\n const supplierName = supplierId\n ? String(\n (await firestore\n .collection('hosts')\n .doc(hostId)\n .collection('suppliers')\n .doc(supplierId)\n .get()\n .then((snapshot) => snapshot.get('name'))\n .catch(() => '')) ?? '',\n ).trim()\n : ''\n void notifyHostManagers(hostId, {\n type: 'content.order',\n title: `Supplier shipped ${orderLabel}${outstanding > 0 ? ` — ${outstanding} line${outstanding === 1 ? '' : 's'} still to ship` : ''}`,\n body:\n `${supplierName || 'Your supplier'} shipped their part of order ` +\n `${orderLabel} on {site}.` +\n (trackingNumber\n ? ` Tracking: ${[carrier, trackingNumber].filter(Boolean).join(' ')}.`\n : ' No tracking number was given.') +\n (outstanding > 0\n ? ` ${outstanding} line${outstanding === 1 ? ' is' : 's are'} still to ship.`\n : ''),\n link: `/${hostId}/products`,\n })\n return res.status(200).json(outcome.body)\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Update failed' })\n }\n}\n"],"names":["CommerceModel","firebaseAdmin","notifyHostManagers","escapeHtml","createHmac","timingSafeEqual","tokenSigningSecret","tokenMatches","stored","presented","expected","a","Buffer","from","b","length","Uint8Array","resolvePostingSupplier","hostId","orderId","order","secret","matched","supplierId","orderSupplierIds","update","digest","slice","supplierUpdateHandler","req","res","source","method","query","body","JSON","parse","String","token","trackingNumber","carrier","status","json","error","test","firestore","app","orderRef","collection","doc","setHeader","field","name","value","input","label","send","outcome","runTransaction","transaction","orderSnapshot","get","exists","liftLegacyOrder","data","suppliers","postingSupplier","myLines","supplierLineItemIds","lineItems","map","_line","index","coveredBefore","coveredLineItemIds","every","has","coveredAfter","Set","nextStatus","statusAfterFulfilling","canTransitionOrder","fulfillment","id","Date","now","toString","lineItemIds","atMs","remaining","filter","set","fulfillments","timeline","appendOrderEvent","merge","ok","orderStatus","outstanding","Number","orderLabel","formatOrderNumber","supplierName","then","snapshot","catch","trim","type","title","Boolean","join","link","console"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/supplier-update.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 * as Aglyn from '@aglyn/aglyn/server'\nimport * as CommerceModel from '../model'\nimport { firebaseAdmin, notifyHostManagers } from '@aglyn/tenant-data-admin'\nimport { escapeHtml } from '../utils/escape-html'\nimport { createHmac, timingSafeEqual } from 'crypto'\nimport { tokenSigningSecret } from './download'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { ORDER_FULFILLED_EVENT } from '../model/order-events'\nimport { fulfillmentEventView, stageOrderEvent } from './order-events'\nimport { type PluginApiHandler } from '@aglyn/aglyn/server'\n\n/**\n * Constant-time compare for the per-order supplier token (AGL-2268).\n *\n * `!==` on a secret leaks its prefix through response timing, and this token is\n * a bearer credential for a route with no account behind it — the only thing\n * standing between the open internet and marking a merchant's order shipped.\n * `download.ts` has compared its own token this way since it shipped; this is\n * the sibling that did not.\n *\n * Length is compared first and OUTSIDE the constant-time call, because\n * `timingSafeEqual` throws on a length mismatch. That leaks the token's LENGTH\n * and nothing else, which is the same concession `download.ts` makes.\n */\nfunction tokenMatches(stored: unknown, presented: string): boolean {\n const expected = typeof stored === 'string' ? stored : ''\n if (!expected || !presented) return false\n const a = Buffer.from(presented)\n const b = Buffer.from(expected)\n if (a.length !== b.length) return false\n return timingSafeEqual(new Uint8Array(a), new Uint8Array(b))\n}\n\n/**\n * WHICH supplier is posting (AGL-2455), and the observation that makes the\n * issue's \"structural blocker\" not structural after all.\n *\n * The order document holds ONE `supplierToken` field, so the issue's reading\n * was that scoping lines per supplier would strand every other supplier's lines\n * permanently: only the last token written could authenticate, and the others\n * would have no valid credential at all. That reading is right about the stored\n * field and wrong about the token.\n *\n * The token is not a random secret that has to be stored to be known. It is\n * `HMAC(hostId:orderId:supplierId)` under `TOKEN_SIGNING_SECRET`\n * (`billing-webhook.ts`), a pure function of three identifiers the order\n * already carries — `supplierId` is stamped onto every line at purchase time.\n * So the expected token for EVERY supplier on the order can be re-derived here\n * and compared, which both identifies the poster and lets every supplier\n * authenticate. No schema change, no migration, no map.\n *\n * Every candidate is compared even after a match, so the work done is a\n * function of the order's supplier count and not of which supplier posted.\n *\n * Returns `null` when nothing matches; the stored-scalar fallback is the\n * caller's, because only it knows whether that fallback is ambiguous.\n */\nfunction resolvePostingSupplier(\n hostId: string,\n orderId: string,\n order: CommerceModel.HostOrder,\n presented: string,\n): string | null {\n let secret: string\n try {\n secret = tokenSigningSecret()\n } catch {\n // Unset secret: no token could have been MINTED either, so there is nothing\n // to derive. Fall through to the stored scalar rather than throwing a 500\n // at a supplier who cannot do anything about it.\n return null\n }\n let matched: string | null = null\n for (const supplierId of CommerceModel.orderSupplierIds(order)) {\n const expected = createHmac('sha256', secret)\n .update(`${hostId}:${orderId}:${supplierId}`)\n .digest('hex')\n .slice(0, 32)\n if (tokenMatches(expected, presented)) matched = supplierId\n }\n return matched\n}\n\n\n/**\n * Supplier tracking callback (AGL-289): the routed order carried a\n * per-order token; posting (or GET-ing, for email links) tracking with\n * it fulfills the order. Token-gated — suppliers have no Aglyn account.\n */\nexport const supplierUpdateHandler: PluginApiHandler = async (req, res) => {\n const source = req.method === 'POST' ? { ...req.query, ...(typeof req.body === 'string' ? JSON.parse(req.body || '{}') : (req.body ?? {})) } : req.query\n const hostId = String(source.hostId ?? '')\n const orderId = String(source.orderId ?? '')\n const token = String(source.token ?? '')\n const trackingNumber = String(source.trackingNumber ?? '').slice(0, 60)\n const carrier = String(source.carrier ?? '').slice(0, 40)\n if (!hostId || !orderId || !token) {\n return res.status(400).json({ error: 'Missing hostId, orderId, or token' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which fell into the catch below and answered 500 to what is a 400\n // (AGL-2455). `fulfill-order.ts` has had this guard since it shipped; this is\n // the sibling route that did not.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId, orderId, or token' })\n }\n\n try {\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = firestore\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n // A GET NEVER MOVES THE ORDER (AGL-2268). The supplier email carries this\n // URL, and a GET that fulfils means every link scanner, spam filter,\n // preview generator and browser prefetch on the path between us and the\n // supplier's inbox marks the order shipped — before anything shipped, and\n // with no tracking number on it. The link still works and the email is\n // unchanged: a GET renders a one-button page that POSTs the same\n // parameters, so the supplier's experience is one extra click and the\n // machines that open mail for a living take no action at all.\n if (req.method === 'GET') {\n res.setHeader('Content-Type', 'text/html')\n const field = (name: string, value: string) =>\n `<input type=\"hidden\" name=\"${name}\" value=\"${escapeHtml(value)}\">`\n // The carrier and the number are FIELDS the supplier fills in\n // (AGL-3432), so the emailed link needs no placeholders for them to\n // edit in the URL. A value a link does carry arrives filled in.\n const input = (name: string, label: string, value: string) =>\n `<p><label>${label}<br>` +\n `<input type=\"text\" name=\"${name}\" value=\"${escapeHtml(value)}\"></label></p>`\n return res.status(200).send(\n '<h3>Record this shipment</h3>' +\n '<p>Enter the carrier and tracking number, then press the button ' +\n 'to record it against the order.</p>' +\n '<form method=\"POST\">' +\n field('hostId', hostId) +\n field('orderId', orderId) +\n field('token', token) +\n input('carrier', 'Carrier', carrier) +\n input('trackingNumber', 'Tracking number', trackingNumber) +\n '<button type=\"submit\">Mark as shipped</button>' +\n '</form>',\n )\n }\n\n // THE READ, THE TRANSITION CHECK AND THE WRITE ARE ONE ACT (AGL-2268).\n // They used to be a plain `get()`, a check, and a `set(…, {merge:true})`,\n // which is the exact stale-read hole AGL-1808/1818/1819 closed on the\n // console's own fulfil, cancel and refund routes — reopened here, on the\n // one door with no account behind it. A supplier POST racing a refund read\n // `paid`, the refund landed, and the POST then wrote `fulfilled` over\n // `refunded`. `ORDER_TRANSITIONS` says `refunded: []`, and the cost is not\n // cosmetic: `gate.ts`, `download.ts`, `membership-account.ts` and\n // `reviews.ts` all withdraw a shopper's entitlement by matching that\n // literal, so the refunded buyer got their downloads back.\n const outcome = await firebaseAdmin\n .app()\n .firestore()\n .runTransaction(async (transaction) => {\n const orderSnapshot = await transaction.get(orderRef)\n if (!orderSnapshot.exists) {\n return { status: 404, body: { error: 'Unknown order' } as any }\n }\n const order = CommerceModel.liftLegacyOrder(orderSnapshot.data() as any)\n // ONE SUPPLIER SHIPS ONE SUPPLIER'S LINES (AGL-2455).\n //\n // `lineItemIds` used to be every index on the order and the status was\n // written as the literal `'fulfilled'`, so the first supplier to post\n // marked the whole order shipped — lines they had never seen included —\n // and the second supplier's POST met a 409. The buyer was told\n // everything shipped with one carrier and one tracking number.\n const suppliers = CommerceModel.orderSupplierIds(order)\n const postingSupplier = resolvePostingSupplier(\n hostId,\n orderId,\n order,\n token,\n )\n let myLines: number[]\n if (postingSupplier) {\n myLines = CommerceModel.supplierLineItemIds(order, postingSupplier)\n } else if (tokenMatches(orderSnapshot.get('supplierToken'), token)) {\n // The STORED scalar matched but no supplier on the order derives to\n // it — an order whose lines carry no `supplierId`, which is every\n // order routed before that field was stamped.\n //\n // With at most one supplier there is only one door, so claiming every\n // line is the same answer this route has always given and is right.\n // With TWO OR MORE, the scalar cannot say whose token it is, and\n // guessing would either close lines a supplier never shipped (the\n // defect) or strand them (the naive fix). REFUSED LOUDLY instead:\n // the merchant fulfils from the console, where they can see the\n // lines, and the message says so rather than leaving them to work it\n // out from an order that silently went quiet.\n if (suppliers.length > 1) {\n return {\n status: 409,\n body: {\n error:\n 'This order has more than one supplier and the link cannot ' +\n 'say which of them you are. Nothing was changed. Please ask ' +\n 'the merchant to record this shipment from their console.',\n } as any,\n }\n }\n myLines = (order.lineItems ?? []).map((_line, index) => index)\n } else {\n return { status: 403, body: { error: 'Invalid token' } as any }\n }\n if (myLines.length === 0) {\n return {\n status: 409,\n body: { error: 'No lines on this order are yours' } as any,\n }\n }\n const coveredBefore = CommerceModel.coveredLineItemIds(order)\n if (myLines.every((index) => coveredBefore.has(index))) {\n // Every line of theirs is already shipped: a redelivered POST, or the\n // supplier pressing the emailed button twice. Refused rather than\n // appending a second copy of the same fulfillment — the same rule\n // `fulfill-order.ts` applies to a retried click.\n return {\n status: 409,\n body: {\n error:\n suppliers.length > 1\n ? 'Your lines on this order are already marked shipped'\n : `Order is already ${order.status}`,\n } as any,\n }\n }\n const coveredAfter = new Set([...coveredBefore, ...myLines])\n // COMPUTED, not written as a literal. `partially_fulfilled` has been in\n // `ORDER_TRANSITIONS` since orders shipped and nothing ever wrote it.\n const nextStatus = CommerceModel.statusAfterFulfilling(\n order,\n coveredAfter,\n )\n // Re-asked inside the transaction that writes, as AGL-2268 established:\n // a supplier POST racing a refund must not write over `refunded`. Only\n // when the status actually MOVES — a second supplier posting onto an\n // already `partially_fulfilled` order changes nothing about the status\n // and must not be refused by a table that has no self-edge.\n if (\n nextStatus !== order.status &&\n !CommerceModel.canTransitionOrder(order.status, nextStatus)\n ) {\n return {\n status: 409,\n body: { error: `Order is already ${order.status}` } as any,\n }\n }\n // The units still open on the supplier's lines (AGL-3611): the\n // merchant may already have shipped part of one from the console.\n const remainingByLine = new Map(\n CommerceModel.orderLineFulfillmentStates(order).map((state) => [\n state.lineItemId,\n state.remainingQuantity,\n ]),\n )\n const shippedLines = myLines\n .map((index) => ({ lineItemId: index, quantity: remainingByLine.get(index) ?? 0 }))\n .filter((entry) => entry.quantity > 0)\n const fulfillment: CommerceModel.OrderFulfillment = {\n id: `supplier-${Date.now().toString(36)}`,\n lineItemIds: shippedLines.map((entry) => entry.lineItemId),\n lines: shippedLines,\n ...(carrier && trackingNumber\n ? (() => {\n const trackingUrl = CommerceModel.trackingUrlFor(carrier, trackingNumber)\n return trackingUrl ? { trackingUrl } : {}\n })()\n : {}),\n ...(carrier ? { carrier } : {}),\n ...(trackingNumber ? { trackingNumber } : {}),\n atMs: Date.now(),\n }\n const remaining = (order.lineItems ?? []).filter(\n (_line, index) => !coveredAfter.has(index),\n ).length\n const shipped = {\n status: nextStatus,\n fulfillments: [...(order.fulfillments ?? []), fulfillment],\n updatedAtMs: Date.now(),\n timeline: CommerceModel.appendOrderEvent(\n order,\n nextStatus,\n `Supplier shipped ${myLines.length} of ${\n (order.lineItems ?? []).length\n } line${(order.lineItems ?? []).length === 1 ? '' : 's'}` +\n (trackingNumber\n ? ` — ${carrier || 'tracking'} ${trackingNumber}`\n : '') +\n (remaining > 0\n ? `. ${remaining} line${remaining === 1 ? '' : 's'} still to ship.`\n : ''),\n ),\n }\n transaction.set(orderRef, shipped, { merge: true })\n stageOrderEvent(transaction, ORDER_FULFILLED_EVENT, { hostId, orderId, key: fulfillment.id, order: { ...orderSnapshot.data(), ...shipped }, extra: { fulfillment: fulfillmentEventView(order, fulfillment) } })\n return {\n status: 200,\n body: { ok: true, lineItemIds: myLines, orderStatus: nextStatus } as any,\n order,\n nextStatus,\n remaining,\n supplierId: postingSupplier,\n fulfillmentId: fulfillment.id,\n }\n })\n if (outcome.status !== 200) {\n return res.status(outcome.status).json(outcome.body)\n }\n // The merchant is told what is STILL OUTSTANDING (AGL-2455). \"Supplier\n // shipped #1042\" on an order where one of three suppliers has posted reads\n // as done, which is the same misreport the status literal made — the\n // merchant would stop watching an order that is two thirds unshipped.\n const outstanding = Number((outcome as any).remaining ?? 0)\n const orderLabel = CommerceModel.formatOrderNumber(\n outcome.order as CommerceModel.HostOrder,\n orderId,\n )\n // Which supplier, which order, where, and the tracking (AGL-3432).\n const supplierId = (outcome as any).supplierId as string | null\n const supplierName = supplierId\n ? String(\n (await firestore\n .collection('hosts')\n .doc(hostId)\n .collection('suppliers')\n .doc(supplierId)\n .get()\n .then((snapshot) => snapshot.get('name'))\n .catch(() => '')) ?? '',\n ).trim()\n : ''\n void notifyHostManagers(hostId, {\n type: 'content.order',\n title: `Supplier shipped ${orderLabel}${outstanding > 0 ? ` — ${outstanding} line${outstanding === 1 ? '' : 's'} still to ship` : ''}`,\n body:\n `${supplierName || 'Your supplier'} shipped their part of order ` +\n `${orderLabel} on {site}.` +\n (trackingNumber\n ? ` Tracking: ${[carrier, trackingNumber].filter(Boolean).join(' ')}.`\n : ' No tracking number was given.') +\n (outstanding > 0\n ? ` ${outstanding} line${outstanding === 1 ? ' is' : 's are'} still to ship.`\n : ''),\n link: `/${hostId}/products`,\n })\n // …and the buyer hears their parcel is on its way (AGL-3610).\n await notifyOrderBuyer({ hostId, orderId }, 'shipped', { fulfillmentId: (outcome as any).fulfillmentId })\n return res.status(200).json(outcome.body)\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Update failed' })\n }\n}\n"],"names":["CommerceModel","firebaseAdmin","notifyHostManagers","escapeHtml","createHmac","timingSafeEqual","tokenSigningSecret","notifyOrderBuyer","ORDER_FULFILLED_EVENT","fulfillmentEventView","stageOrderEvent","tokenMatches","stored","presented","expected","a","Buffer","from","b","length","Uint8Array","resolvePostingSupplier","hostId","orderId","order","secret","matched","supplierId","orderSupplierIds","update","digest","slice","supplierUpdateHandler","req","res","source","method","query","body","JSON","parse","String","token","trackingNumber","carrier","status","json","error","test","firestore","app","orderRef","collection","doc","setHeader","field","name","value","input","label","send","outcome","runTransaction","transaction","orderSnapshot","get","exists","liftLegacyOrder","data","suppliers","postingSupplier","myLines","supplierLineItemIds","lineItems","map","_line","index","coveredBefore","coveredLineItemIds","every","has","coveredAfter","Set","nextStatus","statusAfterFulfilling","canTransitionOrder","remainingByLine","Map","orderLineFulfillmentStates","state","lineItemId","remainingQuantity","shippedLines","quantity","filter","entry","fulfillment","id","Date","now","toString","lineItemIds","lines","trackingUrl","trackingUrlFor","atMs","remaining","shipped","fulfillments","updatedAtMs","timeline","appendOrderEvent","set","merge","key","extra","ok","orderStatus","fulfillmentId","outstanding","Number","orderLabel","formatOrderNumber","supplierName","then","snapshot","catch","trim","type","title","Boolean","join","link","console"],"mappings":"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"}
@@ -0,0 +1,47 @@
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 PluginTaxAddress, type PluginTaxEngineQuote } from '@aglyn/aglyn/plugin-manager/plugin-tax-profile';
18
+ import { type OrderTaxEngineStamp } from '../model/commerce-tax-engine';
19
+ export interface SaleTaxEngineRequest {
20
+ hostId: string;
21
+ settings: {
22
+ mode?: string;
23
+ pricesIncludeTax?: boolean;
24
+ } | null | undefined;
25
+ channel: 'online' | 'pos' | 'invoice';
26
+ currency?: string;
27
+ lines: ReadonlyArray<{
28
+ id: string;
29
+ productId?: string;
30
+ variantId?: string;
31
+ sku?: string;
32
+ description?: string;
33
+ quantity: number;
34
+ /** The line's charged amount, after any discount on it, exclusive of tax. */
35
+ amountCents: number;
36
+ exempt?: boolean;
37
+ }>;
38
+ discountCents?: number;
39
+ shippingCents?: number;
40
+ shipTo?: PluginTaxAddress | null;
41
+ customerEmail?: string | null;
42
+ }
43
+ export interface SaleTaxEngineResult {
44
+ quote: PluginTaxEngineQuote | null;
45
+ stamp: OrderTaxEngineStamp | null;
46
+ }
47
+ export declare function quoteSaleTaxWithEngine(request: SaleTaxEngineRequest): Promise<SaleTaxEngineResult>;
@@ -0,0 +1,105 @@
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 { pluginTaxEngine, quotePluginTaxEngine } from "@aglyn/aglyn/plugin-manager/plugin-tax-profile";
18
+ import { storeTaxAllowsEngine } from "../model/commerce-tax-engine.js";
19
+ /**
20
+ * Asks the site's outside tax service for a sale's tax (AGL-3631), through
21
+ * core's `core.tax-engine` contract — commerce never learns which plugin or
22
+ * vendor answers.
23
+ *
24
+ * `{ quote: null, stamp: null }` means no service was involved: the store is
25
+ * not on its own rates, no plugin offers an engine, or the site connected
26
+ * none. The caller prices the sale exactly as it did before.
27
+ *
28
+ * `{ quote: null, stamp: { status: 'fallback' } }` means a connected service
29
+ * was asked and did not answer in time or refused. The caller STILL prices
30
+ * the sale its usual way — a checkout that waited on a vendor or failed with
31
+ * it would lose the sale — and writes the stamp on the order so the merchant
32
+ * sees which sales were taxed at the store's own rates instead.
33
+ */ /** How long the status read may take; the quote holds core's own deadline. */ const STATUS_DEADLINE_MS = 2000;
34
+ const NONE = {
35
+ quote: null,
36
+ stamp: null
37
+ };
38
+ async function withDeadline(promise, ms, fallback) {
39
+ let timer;
40
+ try {
41
+ return await Promise.race([
42
+ promise.catch(()=>fallback),
43
+ new Promise((resolve)=>{
44
+ timer = setTimeout(()=>resolve(fallback), ms);
45
+ })
46
+ ]);
47
+ } finally{
48
+ if (timer) clearTimeout(timer);
49
+ }
50
+ }
51
+ export async function quoteSaleTaxWithEngine(request) {
52
+ var _request_shipTo, _request_customerEmail;
53
+ if (!storeTaxAllowsEngine(request.settings)) return NONE;
54
+ const engine = pluginTaxEngine();
55
+ if (!engine || request.lines.length === 0) return NONE;
56
+ const status = await withDeadline(Promise.resolve().then(()=>engine.status(request.hostId)), STATUS_DEADLINE_MS, {
57
+ connected: false
58
+ });
59
+ if (!status.connected || !status.provider) return NONE;
60
+ const provider = status.provider;
61
+ const providerLabel = status.providerLabel || provider;
62
+ const sandbox = status.sandbox === true;
63
+ const outcome = await quotePluginTaxEngine(_extends({
64
+ hostId: request.hostId,
65
+ currency: request.currency || 'usd',
66
+ channel: request.channel,
67
+ lines: request.lines
68
+ }, request.discountCents ? {
69
+ discountCents: request.discountCents
70
+ } : {}, request.shippingCents ? {
71
+ shippingCents: request.shippingCents
72
+ } : {}, {
73
+ shipTo: (_request_shipTo = request.shipTo) != null ? _request_shipTo : null,
74
+ customer: {
75
+ email: (_request_customerEmail = request.customerEmail) != null ? _request_customerEmail : null
76
+ }
77
+ }));
78
+ if ('quote' in outcome) {
79
+ const quote = outcome.quote;
80
+ return {
81
+ quote,
82
+ stamp: {
83
+ provider: quote.provider || provider,
84
+ providerLabel: quote.providerLabel || providerLabel,
85
+ status: 'quoted',
86
+ reason: null,
87
+ sandbox: quote.sandbox
88
+ }
89
+ };
90
+ }
91
+ const failed = outcome;
92
+ console.warn(`[commerce] tax service ${provider} did not price a sale on ${request.hostId} (${failed.reason}): ${failed.message}`);
93
+ return {
94
+ quote: null,
95
+ stamp: {
96
+ provider,
97
+ providerLabel,
98
+ status: 'fallback',
99
+ reason: failed.reason,
100
+ sandbox
101
+ }
102
+ };
103
+ }
104
+
105
+ //# sourceMappingURL=tax-engine-quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/tax-engine-quote.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 {\n pluginTaxEngine,\n quotePluginTaxEngine,\n type PluginTaxAddress,\n type PluginTaxEngineQuote,\n} from '@aglyn/aglyn/plugin-manager/plugin-tax-profile'\nimport { storeTaxAllowsEngine, type OrderTaxEngineStamp } from '../model/commerce-tax-engine'\n\n/**\n * Asks the site's outside tax service for a sale's tax (AGL-3631), through\n * core's `core.tax-engine` contract — commerce never learns which plugin or\n * vendor answers.\n *\n * `{ quote: null, stamp: null }` means no service was involved: the store is\n * not on its own rates, no plugin offers an engine, or the site connected\n * none. The caller prices the sale exactly as it did before.\n *\n * `{ quote: null, stamp: { status: 'fallback' } }` means a connected service\n * was asked and did not answer in time or refused. The caller STILL prices\n * the sale its usual way — a checkout that waited on a vendor or failed with\n * it would lose the sale — and writes the stamp on the order so the merchant\n * sees which sales were taxed at the store's own rates instead.\n */\n\n/** How long the status read may take; the quote holds core's own deadline. */\nconst STATUS_DEADLINE_MS = 2_000\n\nexport interface SaleTaxEngineRequest {\n hostId: string\n settings: { mode?: string; pricesIncludeTax?: boolean } | null | undefined\n channel: 'online' | 'pos' | 'invoice'\n currency?: string\n lines: ReadonlyArray<{\n id: string\n productId?: string\n variantId?: string\n sku?: string\n description?: string\n quantity: number\n /** The line's charged amount, after any discount on it, exclusive of tax. */\n amountCents: number\n exempt?: boolean\n }>\n discountCents?: number\n shippingCents?: number\n shipTo?: PluginTaxAddress | null\n customerEmail?: string | null\n}\n\nexport interface SaleTaxEngineResult {\n quote: PluginTaxEngineQuote | null\n stamp: OrderTaxEngineStamp | null\n}\n\nconst NONE: SaleTaxEngineResult = { quote: null, stamp: null }\n\nasync function withDeadline<T>(promise: Promise<T>, ms: number, fallback: T): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await Promise.race([\n promise.catch(() => fallback),\n new Promise<T>((resolve) => {\n timer = setTimeout(() => resolve(fallback), ms)\n }),\n ])\n } finally {\n if (timer) clearTimeout(timer)\n }\n}\n\nexport async function quoteSaleTaxWithEngine(\n request: SaleTaxEngineRequest,\n): Promise<SaleTaxEngineResult> {\n if (!storeTaxAllowsEngine(request.settings)) return NONE\n const engine = pluginTaxEngine()\n if (!engine || request.lines.length === 0) return NONE\n const status = await withDeadline(\n Promise.resolve().then(() => engine.status(request.hostId)),\n STATUS_DEADLINE_MS,\n { connected: false } as Awaited<ReturnType<typeof engine.status>>,\n )\n if (!status.connected || !status.provider) return NONE\n const provider = status.provider\n const providerLabel = status.providerLabel || provider\n const sandbox = status.sandbox === true\n const outcome = await quotePluginTaxEngine({\n hostId: request.hostId,\n currency: request.currency || 'usd',\n channel: request.channel,\n lines: request.lines,\n ...(request.discountCents ? { discountCents: request.discountCents } : {}),\n ...(request.shippingCents ? { shippingCents: request.shippingCents } : {}),\n shipTo: request.shipTo ?? null,\n customer: { email: request.customerEmail ?? null },\n })\n if ('quote' in outcome) {\n const quote = outcome.quote\n return {\n quote,\n stamp: {\n provider: quote.provider || provider,\n providerLabel: quote.providerLabel || providerLabel,\n status: 'quoted',\n reason: null,\n sandbox: quote.sandbox,\n },\n }\n }\n const failed = outcome as Extract<typeof outcome, { ok: false }>\n console.warn(\n `[commerce] tax service ${provider} did not price a sale on ${request.hostId} (${failed.reason}): ${failed.message}`,\n )\n return {\n quote: null,\n stamp: { provider, providerLabel, status: 'fallback', reason: failed.reason, sandbox },\n }\n}\n"],"names":["pluginTaxEngine","quotePluginTaxEngine","storeTaxAllowsEngine","STATUS_DEADLINE_MS","NONE","quote","stamp","withDeadline","promise","ms","fallback","timer","Promise","race","catch","resolve","setTimeout","clearTimeout","quoteSaleTaxWithEngine","request","settings","engine","lines","length","status","then","hostId","connected","provider","providerLabel","sandbox","outcome","currency","channel","discountCents","shippingCents","shipTo","customer","email","customerEmail","reason","failed","console","warn","message"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,eAAe,EACfC,oBAAoB,QAGf,iDAAgD;AACvD,SAASC,oBAAoB,QAAkC,kCAA8B;AAE7F;;;;;;;;;;;;;;CAcC,GAED,4EAA4E,GAC5E,MAAMC,qBAAqB;AA6B3B,MAAMC,OAA4B;IAAEC,OAAO;IAAMC,OAAO;AAAK;AAE7D,eAAeC,aAAgBC,OAAmB,EAAEC,EAAU,EAAEC,QAAW;IACzE,IAAIC;IACJ,IAAI;QACF,OAAO,MAAMC,QAAQC,IAAI,CAAC;YACxBL,QAAQM,KAAK,CAAC,IAAMJ;YACpB,IAAIE,QAAW,CAACG;gBACdJ,QAAQK,WAAW,IAAMD,QAAQL,WAAWD;YAC9C;SACD;IACH,SAAU;QACR,IAAIE,OAAOM,aAAaN;IAC1B;AACF;AAEA,OAAO,eAAeO,uBACpBC,OAA6B;QAqBnBA,iBACWA;IApBrB,IAAI,CAACjB,qBAAqBiB,QAAQC,QAAQ,GAAG,OAAOhB;IACpD,MAAMiB,SAASrB;IACf,IAAI,CAACqB,UAAUF,QAAQG,KAAK,CAACC,MAAM,KAAK,GAAG,OAAOnB;IAClD,MAAMoB,SAAS,MAAMjB,aACnBK,QAAQG,OAAO,GAAGU,IAAI,CAAC,IAAMJ,OAAOG,MAAM,CAACL,QAAQO,MAAM,IACzDvB,oBACA;QAAEwB,WAAW;IAAM;IAErB,IAAI,CAACH,OAAOG,SAAS,IAAI,CAACH,OAAOI,QAAQ,EAAE,OAAOxB;IAClD,MAAMwB,WAAWJ,OAAOI,QAAQ;IAChC,MAAMC,gBAAgBL,OAAOK,aAAa,IAAID;IAC9C,MAAME,UAAUN,OAAOM,OAAO,KAAK;IACnC,MAAMC,UAAU,MAAM9B,qBAAqB;QACzCyB,QAAQP,QAAQO,MAAM;QACtBM,UAAUb,QAAQa,QAAQ,IAAI;QAC9BC,SAASd,QAAQc,OAAO;QACxBX,OAAOH,QAAQG,KAAK;OAChBH,QAAQe,aAAa,GAAG;QAAEA,eAAef,QAAQe,aAAa;IAAC,IAAI,CAAC,GACpEf,QAAQgB,aAAa,GAAG;QAAEA,eAAehB,QAAQgB,aAAa;IAAC,IAAI,CAAC;QACxEC,MAAM,GAAEjB,kBAAAA,QAAQiB,MAAM,YAAdjB,kBAAkB;QAC1BkB,UAAU;YAAEC,KAAK,GAAEnB,yBAAAA,QAAQoB,aAAa,YAArBpB,yBAAyB;QAAK;;IAEnD,IAAI,WAAWY,SAAS;QACtB,MAAM1B,QAAQ0B,QAAQ1B,KAAK;QAC3B,OAAO;YACLA;YACAC,OAAO;gBACLsB,UAAUvB,MAAMuB,QAAQ,IAAIA;gBAC5BC,eAAexB,MAAMwB,aAAa,IAAIA;gBACtCL,QAAQ;gBACRgB,QAAQ;gBACRV,SAASzB,MAAMyB,OAAO;YACxB;QACF;IACF;IACA,MAAMW,SAASV;IACfW,QAAQC,IAAI,CACV,CAAC,uBAAuB,EAAEf,SAAS,yBAAyB,EAAET,QAAQO,MAAM,CAAC,EAAE,EAAEe,OAAOD,MAAM,CAAC,GAAG,EAAEC,OAAOG,OAAO,EAAE;IAEtH,OAAO;QACLvC,OAAO;QACPC,OAAO;YAAEsB;YAAUC;YAAeL,QAAQ;YAAYgB,QAAQC,OAAOD,MAAM;YAAEV;QAAQ;IACvF;AACF"}