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

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 (581) 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/customer-notifications-card.component.d.ts +19 -0
  39. package/src/lib/components/console/customer-notifications-card.component.js +149 -0
  40. package/src/lib/components/console/customer-notifications-card.component.js.map +1 -0
  41. package/src/lib/components/console/host-orders-card.component.js +84 -5
  42. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  43. package/src/lib/components/console/locations-card.component.js +164 -57
  44. package/src/lib/components/console/locations-card.component.js.map +1 -1
  45. package/src/lib/components/console/order-detail-dialog.component.js +209 -61
  46. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  47. package/src/lib/components/console/order-fulfillment-panel.component.d.ts +48 -0
  48. package/src/lib/components/console/order-fulfillment-panel.component.js +542 -0
  49. package/src/lib/components/console/order-fulfillment-panel.component.js.map +1 -0
  50. package/src/lib/components/console/order-invoice.component.d.ts +33 -0
  51. package/src/lib/components/console/order-invoice.component.js +81 -0
  52. package/src/lib/components/console/order-invoice.component.js.map +1 -0
  53. package/src/lib/components/console/order-receipt-resend.component.d.ts +21 -0
  54. package/src/lib/components/console/order-receipt-resend.component.js +203 -0
  55. package/src/lib/components/console/order-receipt-resend.component.js.map +1 -0
  56. package/src/lib/components/console/order-returns.component.d.ts +36 -0
  57. package/src/lib/components/console/order-returns.component.js +142 -0
  58. package/src/lib/components/console/order-returns.component.js.map +1 -0
  59. package/src/lib/components/console/order-shipping-actions.component.d.ts +54 -0
  60. package/src/lib/components/console/order-shipping-actions.component.js +149 -0
  61. package/src/lib/components/console/order-shipping-actions.component.js.map +1 -0
  62. package/src/lib/components/console/order-webhooks-card.component.d.ts +50 -0
  63. package/src/lib/components/console/order-webhooks-card.component.js +623 -0
  64. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -0
  65. package/src/lib/components/console/order-zones.d.ts +155 -0
  66. package/src/lib/components/console/order-zones.js +40 -0
  67. package/src/lib/components/console/order-zones.js.map +1 -0
  68. package/src/lib/components/console/payment-methods-card.component.d.ts +67 -0
  69. package/src/lib/components/console/payment-methods-card.component.js +395 -0
  70. package/src/lib/components/console/payment-methods-card.component.js.map +1 -0
  71. package/src/lib/components/console/pos/pos-api.d.ts +124 -0
  72. package/src/lib/components/console/pos/pos-api.js +101 -0
  73. package/src/lib/components/console/pos/pos-api.js.map +1 -0
  74. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +36 -0
  75. package/src/lib/components/console/pos/pos-cart-panel.component.js +160 -0
  76. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -0
  77. package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +39 -0
  78. package/src/lib/components/console/pos/pos-item-dialog.component.js +352 -0
  79. package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -0
  80. package/src/lib/components/console/pos/pos-product-grid.component.d.ts +47 -0
  81. package/src/lib/components/console/pos/pos-product-grid.component.js +272 -0
  82. package/src/lib/components/console/pos/pos-product-grid.component.js.map +1 -0
  83. package/src/lib/components/console/pos/pos-receipt-panel.component.d.ts +27 -0
  84. package/src/lib/components/console/pos/pos-receipt-panel.component.js +282 -0
  85. package/src/lib/components/console/pos/pos-receipt-panel.component.js.map +1 -0
  86. package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +53 -0
  87. package/src/lib/components/console/pos/pos-tender-dialogs.component.js +445 -0
  88. package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -0
  89. package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +31 -0
  90. package/src/lib/components/console/pos/pos-tender-panel.component.js +640 -0
  91. package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -0
  92. package/src/lib/components/console/pos/use-pos-display.d.ts +43 -0
  93. package/src/lib/components/console/pos/use-pos-display.js +161 -0
  94. package/src/lib/components/console/pos/use-pos-display.js.map +1 -0
  95. package/src/lib/components/console/pos-devices-card.component.d.ts +14 -0
  96. package/src/lib/components/console/pos-devices-card.component.js +546 -0
  97. package/src/lib/components/console/pos-devices-card.component.js.map +1 -0
  98. package/src/lib/components/console/pos-display/brand-screen.d.ts +33 -0
  99. package/src/lib/components/console/pos-display/brand-screen.js +85 -0
  100. package/src/lib/components/console/pos-display/brand-screen.js.map +1 -0
  101. package/src/lib/components/console/pos-display/cart-screen.d.ts +29 -0
  102. package/src/lib/components/console/pos-display/cart-screen.js +166 -0
  103. package/src/lib/components/console/pos-display/cart-screen.js.map +1 -0
  104. package/src/lib/components/console/pos-display/pairing-screen.d.ts +24 -0
  105. package/src/lib/components/console/pos-display/pairing-screen.js +127 -0
  106. package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -0
  107. package/src/lib/components/console/pos-display/pos-display-api.d.ts +90 -0
  108. package/src/lib/components/console/pos-display/pos-display-api.js +140 -0
  109. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -0
  110. package/src/lib/components/console/pos-display/receipt-screen.d.ts +35 -0
  111. package/src/lib/components/console/pos-display/receipt-screen.js +200 -0
  112. package/src/lib/components/console/pos-display/receipt-screen.js.map +1 -0
  113. package/src/lib/components/console/pos-display/tip-screen.d.ts +36 -0
  114. package/src/lib/components/console/pos-display/tip-screen.js +211 -0
  115. package/src/lib/components/console/pos-display/tip-screen.js.map +1 -0
  116. package/src/lib/components/console/pos-display-page.component.d.ts +16 -0
  117. package/src/lib/components/console/pos-display-page.component.js +407 -0
  118. package/src/lib/components/console/pos-display-page.component.js.map +1 -0
  119. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +40 -0
  120. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +289 -0
  121. package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -0
  122. package/src/lib/components/console/pos-ops/pos-last-receipt.component.d.ts +34 -0
  123. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js +61 -0
  124. package/src/lib/components/console/pos-ops/pos-last-receipt.component.js.map +1 -0
  125. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +38 -0
  126. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +129 -0
  127. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -0
  128. package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +37 -0
  129. package/src/lib/components/console/pos-ops/pos-ops-api.js +60 -0
  130. package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -0
  131. package/src/lib/components/console/pos-ops/pos-pin-pad.component.d.ts +48 -0
  132. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js +220 -0
  133. package/src/lib/components/console/pos-ops/pos-pin-pad.component.js.map +1 -0
  134. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.d.ts +63 -0
  135. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js +186 -0
  136. package/src/lib/components/console/pos-ops/pos-receipt-actions.component.js.map +1 -0
  137. package/src/lib/components/console/pos-ops/pos-receipt.d.ts +39 -0
  138. package/src/lib/components/console/pos-ops/pos-receipt.js +182 -0
  139. package/src/lib/components/console/pos-ops/pos-receipt.js.map +1 -0
  140. package/src/lib/components/console/pos-ops/pos-return-dialog.component.d.ts +40 -0
  141. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js +465 -0
  142. package/src/lib/components/console/pos-ops/pos-return-dialog.component.js.map +1 -0
  143. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.d.ts +29 -0
  144. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +253 -0
  145. package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -0
  146. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +34 -0
  147. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +494 -0
  148. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -0
  149. package/src/lib/components/console/pos-ops/pos-shift-report.component.d.ts +37 -0
  150. package/src/lib/components/console/pos-ops/pos-shift-report.component.js +102 -0
  151. package/src/lib/components/console/pos-ops/pos-shift-report.component.js.map +1 -0
  152. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.d.ts +30 -0
  153. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js +277 -0
  154. package/src/lib/components/console/pos-ops/pos-staff-pins-card.component.js.map +1 -0
  155. package/src/lib/components/console/pos-ops/register-ops.d.ts +28 -0
  156. package/src/lib/components/console/pos-ops/register-ops.js +28 -0
  157. package/src/lib/components/console/pos-ops/register-ops.js.map +1 -0
  158. package/src/lib/components/console/pos-ops/use-pos-cashier.d.ts +46 -0
  159. package/src/lib/components/console/pos-ops/use-pos-cashier.js +128 -0
  160. package/src/lib/components/console/pos-ops/use-pos-cashier.js.map +1 -0
  161. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.d.ts +36 -0
  162. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js +64 -0
  163. package/src/lib/components/console/pos-ops/use-pos-sale-receipt.js.map +1 -0
  164. package/src/lib/components/console/pos-page.component.d.ts +13 -5
  165. package/src/lib/components/console/pos-page.component.js +729 -657
  166. package/src/lib/components/console/pos-page.component.js.map +1 -1
  167. package/src/lib/components/console/product-editor-dialog.component.js +51 -7
  168. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  169. package/src/lib/components/console/product-labels-dialog.component.d.ts +13 -0
  170. package/src/lib/components/console/product-labels-dialog.component.js +197 -0
  171. package/src/lib/components/console/product-labels-dialog.component.js.map +1 -0
  172. package/src/lib/components/console/product-register-fields.component.d.ts +19 -0
  173. package/src/lib/components/console/product-register-fields.component.js +241 -0
  174. package/src/lib/components/console/product-register-fields.component.js.map +1 -0
  175. package/src/lib/components/console/product-zones.d.ts +44 -0
  176. package/src/lib/components/console/product-zones.js.map +1 -1
  177. package/src/lib/components/console/products-hub-card.component.js +12 -0
  178. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  179. package/src/lib/components/console/register-hardware-card.component.d.ts +33 -0
  180. package/src/lib/components/console/register-hardware-card.component.js +826 -0
  181. package/src/lib/components/console/register-hardware-card.component.js.map +1 -0
  182. package/src/lib/components/console/registers-card.component.js +24 -5
  183. package/src/lib/components/console/registers-card.component.js.map +1 -1
  184. package/src/lib/components/console/return-actions.d.ts +38 -0
  185. package/src/lib/components/console/return-actions.js +76 -0
  186. package/src/lib/components/console/return-actions.js.map +1 -0
  187. package/src/lib/components/console/return-detail-dialog.component.d.ts +34 -0
  188. package/src/lib/components/console/return-detail-dialog.component.js +718 -0
  189. package/src/lib/components/console/return-detail-dialog.component.js.map +1 -0
  190. package/src/lib/components/console/return-settings-card.component.d.ts +34 -0
  191. package/src/lib/components/console/return-settings-card.component.js +195 -0
  192. package/src/lib/components/console/return-settings-card.component.js.map +1 -0
  193. package/src/lib/components/console/return-zones.d.ts +87 -0
  194. package/src/lib/components/console/return-zones.js +31 -0
  195. package/src/lib/components/console/return-zones.js.map +1 -0
  196. package/src/lib/components/console/returns-card.component.d.ts +45 -0
  197. package/src/lib/components/console/returns-card.component.js +159 -0
  198. package/src/lib/components/console/returns-card.component.js.map +1 -0
  199. package/src/lib/components/console/shipping-settings-card.component.js +161 -5
  200. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
  201. package/src/lib/components/console/shippingeasy-card.component.d.ts +59 -0
  202. package/src/lib/components/console/shippingeasy-card.component.js +378 -0
  203. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -0
  204. package/src/lib/components/console/shipstation-card.component.d.ts +35 -0
  205. package/src/lib/components/console/shipstation-card.component.js +345 -0
  206. package/src/lib/components/console/shipstation-card.component.js.map +1 -0
  207. package/src/lib/components/console/start-return-dialog.component.d.ts +40 -0
  208. package/src/lib/components/console/start-return-dialog.component.js +243 -0
  209. package/src/lib/components/console/start-return-dialog.component.js.map +1 -0
  210. package/src/lib/components/console/stock-movements-card.component.js +2 -1
  211. package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
  212. package/src/lib/components/console/store-settings-card.component.js +2 -66
  213. package/src/lib/components/console/store-settings-card.component.js.map +1 -1
  214. package/src/lib/components/console/store-zones.d.ts +42 -0
  215. package/src/lib/components/console/store-zones.js +39 -0
  216. package/src/lib/components/console/store-zones.js.map +1 -0
  217. package/src/lib/components/order-status.d.ts +36 -0
  218. package/src/lib/components/order-status.js +502 -0
  219. package/src/lib/components/order-status.js.map +1 -0
  220. package/src/lib/components/product-detail.js +41 -2
  221. package/src/lib/components/product-detail.js.map +1 -1
  222. package/src/lib/components/return-request.d.ts +32 -0
  223. package/src/lib/components/return-request.js +576 -0
  224. package/src/lib/components/return-request.js.map +1 -0
  225. package/src/lib/components/storefront-payment-appearance.d.ts +32 -0
  226. package/src/lib/components/storefront-payment-appearance.js +114 -0
  227. package/src/lib/components/storefront-payment-appearance.js.map +1 -0
  228. package/src/lib/components/storefront-payment-element.d.ts +57 -1
  229. package/src/lib/components/storefront-payment-element.js +332 -33
  230. package/src/lib/components/storefront-payment-element.js.map +1 -1
  231. package/src/lib/constants/order-status.d.ts +22 -0
  232. package/src/lib/constants/order-status.js +22 -0
  233. package/src/lib/constants/order-status.js.map +1 -0
  234. package/src/lib/constants/return-request.d.ts +27 -0
  235. package/src/lib/constants/return-request.js +32 -0
  236. package/src/lib/constants/return-request.js.map +1 -0
  237. package/src/lib/constants/stock-movement-query.js +2 -1
  238. package/src/lib/constants/stock-movement-query.js.map +1 -1
  239. package/src/lib/declarations.console-server.js +9 -0
  240. package/src/lib/declarations.console-server.js.map +1 -1
  241. package/src/lib/declarations.server.d.ts +2 -1
  242. package/src/lib/declarations.server.js +47 -1
  243. package/src/lib/declarations.server.js.map +1 -1
  244. package/src/lib/model/buyer-notifications.d.ts +59 -0
  245. package/src/lib/model/buyer-notifications.js +97 -0
  246. package/src/lib/model/buyer-notifications.js.map +1 -0
  247. package/src/lib/model/commerce-orders.d.ts +127 -1
  248. package/src/lib/model/commerce-orders.js +24 -15
  249. package/src/lib/model/commerce-orders.js.map +1 -1
  250. package/src/lib/model/commerce-payment-methods.d.ts +146 -0
  251. package/src/lib/model/commerce-payment-methods.js +247 -0
  252. package/src/lib/model/commerce-payment-methods.js.map +1 -0
  253. package/src/lib/model/commerce-pos-ops.d.ts +437 -0
  254. package/src/lib/model/commerce-pos-ops.js +721 -0
  255. package/src/lib/model/commerce-pos-ops.js.map +1 -0
  256. package/src/lib/model/commerce-pos.d.ts +263 -0
  257. package/src/lib/model/commerce-pos.js +375 -0
  258. package/src/lib/model/commerce-pos.js.map +1 -0
  259. package/src/lib/model/commerce-printers.d.ts +211 -0
  260. package/src/lib/model/commerce-printers.js +181 -0
  261. package/src/lib/model/commerce-printers.js.map +1 -0
  262. package/src/lib/model/commerce-receipt.d.ts +97 -0
  263. package/src/lib/model/commerce-receipt.js +180 -0
  264. package/src/lib/model/commerce-receipt.js.map +1 -0
  265. package/src/lib/model/commerce-returns.d.ts +207 -0
  266. package/src/lib/model/commerce-returns.js +300 -0
  267. package/src/lib/model/commerce-returns.js.map +1 -0
  268. package/src/lib/model/commerce-shipping.d.ts +44 -1
  269. package/src/lib/model/commerce-shipping.js +53 -9
  270. package/src/lib/model/commerce-shipping.js.map +1 -1
  271. package/src/lib/model/commerce-tax-engine.d.ts +90 -0
  272. package/src/lib/model/commerce-tax-engine.js +129 -0
  273. package/src/lib/model/commerce-tax-engine.js.map +1 -0
  274. package/src/lib/model/commerce.d.ts +88 -2
  275. package/src/lib/model/commerce.js +89 -1
  276. package/src/lib/model/commerce.js.map +1 -1
  277. package/src/lib/model/index.d.ts +15 -0
  278. package/src/lib/model/index.js +15 -0
  279. package/src/lib/model/index.js.map +1 -1
  280. package/src/lib/model/order-events.d.ts +154 -0
  281. package/src/lib/model/order-events.js +153 -0
  282. package/src/lib/model/order-events.js.map +1 -0
  283. package/src/lib/model/order-fulfillment.d.ts +117 -0
  284. package/src/lib/model/order-fulfillment.js +217 -0
  285. package/src/lib/model/order-fulfillment.js.map +1 -0
  286. package/src/lib/model/order-history.d.ts +58 -0
  287. package/src/lib/model/order-history.js +22 -0
  288. package/src/lib/model/order-history.js.map +1 -0
  289. package/src/lib/model/order-list-fields.d.ts +9 -1
  290. package/src/lib/model/order-list-fields.js +7 -1
  291. package/src/lib/model/order-list-fields.js.map +1 -1
  292. package/src/lib/model/order-shipping-export.d.ts +91 -0
  293. package/src/lib/model/order-shipping-export.js +192 -0
  294. package/src/lib/model/order-shipping-export.js.map +1 -0
  295. package/src/lib/model/order-status-view.d.ts +103 -0
  296. package/src/lib/model/order-status-view.js +156 -0
  297. package/src/lib/model/order-status-view.js.map +1 -0
  298. package/src/lib/model/order-webhooks.d.ts +142 -0
  299. package/src/lib/model/order-webhooks.js +91 -0
  300. package/src/lib/model/order-webhooks.js.map +1 -0
  301. package/src/lib/model/product-channel.d.ts +56 -0
  302. package/src/lib/model/product-channel.js +86 -0
  303. package/src/lib/model/product-channel.js.map +1 -0
  304. package/src/lib/model/product-modifiers.d.ts +80 -0
  305. package/src/lib/model/product-modifiers.js +140 -0
  306. package/src/lib/model/product-modifiers.js.map +1 -0
  307. package/src/lib/model/shippingeasy.d.ts +94 -0
  308. package/src/lib/model/shippingeasy.js +267 -0
  309. package/src/lib/model/shippingeasy.js.map +1 -0
  310. package/src/lib/model/shipstation.d.ts +125 -0
  311. package/src/lib/model/shipstation.js +399 -0
  312. package/src/lib/model/shipstation.js.map +1 -0
  313. package/src/lib/model/smart-collection-reads.d.ts +32 -0
  314. package/src/lib/model/smart-collection-reads.js +63 -0
  315. package/src/lib/model/smart-collection-reads.js.map +1 -0
  316. package/src/lib/model/tracking-url.d.ts +74 -0
  317. package/src/lib/model/tracking-url.js +159 -0
  318. package/src/lib/model/tracking-url.js.map +1 -0
  319. package/src/lib/plugin-config.d.ts +13 -0
  320. package/src/lib/plugin-config.js +77 -5
  321. package/src/lib/plugin-config.js.map +1 -1
  322. package/src/lib/plugin.js +23 -0
  323. package/src/lib/plugin.js.map +1 -1
  324. package/src/lib/pos-ops-config.d.ts +39 -0
  325. package/src/lib/pos-ops-config.js +88 -0
  326. package/src/lib/pos-ops-config.js.map +1 -0
  327. package/src/lib/printing/print-document.d.ts +106 -0
  328. package/src/lib/printing/print-document.js +464 -0
  329. package/src/lib/printing/print-document.js.map +1 -0
  330. package/src/lib/printing/product-labels.d.ts +58 -0
  331. package/src/lib/printing/product-labels.js +116 -0
  332. package/src/lib/printing/product-labels.js.map +1 -0
  333. package/src/lib/printing/render-epson.d.ts +57 -0
  334. package/src/lib/printing/render-epson.js +135 -0
  335. package/src/lib/printing/render-epson.js.map +1 -0
  336. package/src/lib/printing/render-star.d.ts +45 -0
  337. package/src/lib/printing/render-star.js +100 -0
  338. package/src/lib/printing/render-star.js.map +1 -0
  339. package/src/lib/printing/render-text.d.ts +25 -0
  340. package/src/lib/printing/render-text.js +53 -0
  341. package/src/lib/printing/render-text.js.map +1 -0
  342. package/src/lib/server/api-v1/openapi.js +27 -4
  343. package/src/lib/server/api-v1/openapi.js.map +1 -1
  344. package/src/lib/server/api-v1/order-view.d.ts +67 -0
  345. package/src/lib/server/api-v1/order-view.js +120 -0
  346. package/src/lib/server/api-v1/order-view.js.map +1 -0
  347. package/src/lib/server/api-v1/orders-and-products.js +58 -65
  348. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  349. package/src/lib/server/billing-webhook.js +135 -28
  350. package/src/lib/server/billing-webhook.js.map +1 -1
  351. package/src/lib/server/cancel-order.js +29 -0
  352. package/src/lib/server/cancel-order.js.map +1 -1
  353. package/src/lib/server/carrier-rates-availability.d.ts +26 -0
  354. package/src/lib/server/carrier-rates-availability.js +76 -0
  355. package/src/lib/server/carrier-rates-availability.js.map +1 -0
  356. package/src/lib/server/carrier-shipping.d.ts +84 -0
  357. package/src/lib/server/carrier-shipping.js +135 -0
  358. package/src/lib/server/carrier-shipping.js.map +1 -0
  359. package/src/lib/server/cart-checkout.d.ts +2 -0
  360. package/src/lib/server/cart-checkout.js +226 -22
  361. package/src/lib/server/cart-checkout.js.map +1 -1
  362. package/src/lib/server/checkout-extras.d.ts +64 -0
  363. package/src/lib/server/checkout-extras.js +157 -0
  364. package/src/lib/server/checkout-extras.js.map +1 -0
  365. package/src/lib/server/{feed.d.ts → checkout-status.d.ts} +2 -7
  366. package/src/lib/server/checkout-status.js +111 -0
  367. package/src/lib/server/checkout-status.js.map +1 -0
  368. package/src/lib/server/checkout.js +86 -9
  369. package/src/lib/server/checkout.js.map +1 -1
  370. package/src/lib/server/draft-order.js +34 -5
  371. package/src/lib/server/draft-order.js.map +1 -1
  372. package/src/lib/server/fulfill-order.d.ts +127 -10
  373. package/src/lib/server/fulfill-order.js +451 -49
  374. package/src/lib/server/fulfill-order.js.map +1 -1
  375. package/src/lib/server/legacy-feed.d.ts +28 -0
  376. package/src/lib/server/legacy-feed.js +52 -0
  377. package/src/lib/server/legacy-feed.js.map +1 -0
  378. package/src/lib/server/native-checkout.d.ts +34 -15
  379. package/src/lib/server/native-checkout.js +32 -17
  380. package/src/lib/server/native-checkout.js.map +1 -1
  381. package/src/lib/server/order-event-host-emit.d.ts +23 -0
  382. package/src/lib/server/order-event-host-emit.js +30 -0
  383. package/src/lib/server/order-event-host-emit.js.map +1 -0
  384. package/src/lib/server/order-event-triggers.d.ts +37 -0
  385. package/src/lib/server/order-event-triggers.js +119 -0
  386. package/src/lib/server/order-event-triggers.js.map +1 -0
  387. package/src/lib/server/order-events.d.ts +62 -0
  388. package/src/lib/server/order-events.js +109 -0
  389. package/src/lib/server/order-events.js.map +1 -0
  390. package/src/lib/server/order-history.d.ts +23 -0
  391. package/src/lib/server/order-history.js +65 -0
  392. package/src/lib/server/order-history.js.map +1 -0
  393. package/src/lib/server/order-notifications.d.ts +185 -0
  394. package/src/lib/server/order-notifications.js +567 -0
  395. package/src/lib/server/order-notifications.js.map +1 -0
  396. package/src/lib/server/order-receipt-send.d.ts +39 -0
  397. package/src/lib/server/order-receipt-send.js +151 -0
  398. package/src/lib/server/order-receipt-send.js.map +1 -0
  399. package/src/lib/server/order-status-token.d.ts +31 -0
  400. package/src/lib/server/order-status-token.js +75 -0
  401. package/src/lib/server/order-status-token.js.map +1 -0
  402. package/src/lib/server/order-status.d.ts +58 -0
  403. package/src/lib/server/order-status.js +141 -0
  404. package/src/lib/server/order-status.js.map +1 -0
  405. package/src/lib/server/order-webhooks.d.ts +108 -0
  406. package/src/lib/server/order-webhooks.js +622 -0
  407. package/src/lib/server/order-webhooks.js.map +1 -0
  408. package/src/lib/server/orders-shipping-prepare.d.ts +26 -0
  409. package/src/lib/server/orders-shipping-prepare.js +121 -0
  410. package/src/lib/server/orders-shipping-prepare.js.map +1 -0
  411. package/src/lib/server/payment-method-domains.d.ts +209 -0
  412. package/src/lib/server/payment-method-domains.js +444 -0
  413. package/src/lib/server/payment-method-domains.js.map +1 -0
  414. package/src/lib/server/payment-methods.d.ts +77 -0
  415. package/src/lib/server/payment-methods.js +284 -0
  416. package/src/lib/server/payment-methods.js.map +1 -0
  417. package/src/lib/server/pos-auth.d.ts +50 -0
  418. package/src/lib/server/pos-auth.js +121 -0
  419. package/src/lib/server/pos-auth.js.map +1 -0
  420. package/src/lib/server/pos-customer.d.ts +49 -0
  421. package/src/lib/server/pos-customer.js +257 -0
  422. package/src/lib/server/pos-customer.js.map +1 -0
  423. package/src/lib/server/pos-display.d.ts +57 -0
  424. package/src/lib/server/pos-display.js +419 -0
  425. package/src/lib/server/pos-display.js.map +1 -0
  426. package/src/lib/server/pos-fee-month.d.ts +34 -0
  427. package/src/lib/server/pos-fee-month.js +36 -0
  428. package/src/lib/server/pos-fee-month.js.map +1 -0
  429. package/src/lib/server/pos-ops-gate.d.ts +161 -0
  430. package/src/lib/server/pos-ops-gate.js +295 -0
  431. package/src/lib/server/pos-ops-gate.js.map +1 -0
  432. package/src/lib/server/pos-ops-routes.d.ts +22 -0
  433. package/src/lib/server/pos-ops-routes.js +36 -0
  434. package/src/lib/server/pos-ops-routes.js.map +1 -0
  435. package/src/lib/server/pos-order.d.ts +1 -18
  436. package/src/lib/server/pos-order.js +222 -42
  437. package/src/lib/server/pos-order.js.map +1 -1
  438. package/src/lib/server/pos-payment.d.ts +39 -0
  439. package/src/lib/server/pos-payment.js +922 -0
  440. package/src/lib/server/pos-payment.js.map +1 -0
  441. package/src/lib/server/pos-print.d.ts +82 -0
  442. package/src/lib/server/pos-print.js +193 -0
  443. package/src/lib/server/pos-print.js.map +1 -0
  444. package/src/lib/server/pos-readers.d.ts +27 -0
  445. package/src/lib/server/pos-readers.js +276 -0
  446. package/src/lib/server/pos-readers.js.map +1 -0
  447. package/src/lib/server/pos-refund-authority.d.ts +60 -0
  448. package/src/lib/server/pos-refund-authority.js +72 -0
  449. package/src/lib/server/pos-refund-authority.js.map +1 -0
  450. package/src/lib/server/pos-return.d.ts +58 -0
  451. package/src/lib/server/pos-return.js +891 -0
  452. package/src/lib/server/pos-return.js.map +1 -0
  453. package/src/lib/server/pos-sale-stamp.d.ts +66 -0
  454. package/src/lib/server/pos-sale-stamp.js +84 -0
  455. package/src/lib/server/pos-sale-stamp.js.map +1 -0
  456. package/src/lib/server/pos-sale.d.ts +170 -0
  457. package/src/lib/server/pos-sale.js +461 -0
  458. package/src/lib/server/pos-sale.js.map +1 -0
  459. package/src/lib/server/pos-shift.d.ts +45 -0
  460. package/src/lib/server/pos-shift.js +484 -0
  461. package/src/lib/server/pos-shift.js.map +1 -0
  462. package/src/lib/server/pos-staff-pin.d.ts +26 -0
  463. package/src/lib/server/pos-staff-pin.js +339 -0
  464. package/src/lib/server/pos-staff-pin.js.map +1 -0
  465. package/src/lib/server/pos-stripe.d.ts +91 -0
  466. package/src/lib/server/pos-stripe.js +129 -0
  467. package/src/lib/server/pos-stripe.js.map +1 -0
  468. package/src/lib/server/pos-terminal-connection-token.d.ts +48 -0
  469. package/src/lib/server/pos-terminal-connection-token.js +166 -0
  470. package/src/lib/server/pos-terminal-connection-token.js.map +1 -0
  471. package/src/lib/server/pos-terminal.d.ts +218 -0
  472. package/src/lib/server/pos-terminal.js +1014 -0
  473. package/src/lib/server/pos-terminal.js.map +1 -0
  474. package/src/lib/server/print-queue.d.ts +124 -0
  475. package/src/lib/server/print-queue.js +301 -0
  476. package/src/lib/server/print-queue.js.map +1 -0
  477. package/src/lib/server/printer-poll.d.ts +75 -0
  478. package/src/lib/server/printer-poll.js +325 -0
  479. package/src/lib/server/printer-poll.js.map +1 -0
  480. package/src/lib/server/printer-secret.d.ts +39 -0
  481. package/src/lib/server/printer-secret.js +56 -0
  482. package/src/lib/server/printer-secret.js.map +1 -0
  483. package/src/lib/server/printers.d.ts +114 -0
  484. package/src/lib/server/printers.js +546 -0
  485. package/src/lib/server/printers.js.map +1 -0
  486. package/src/lib/server/product-catalog.d.ts +42 -0
  487. package/src/lib/server/product-catalog.js +305 -0
  488. package/src/lib/server/product-catalog.js.map +1 -0
  489. package/src/lib/server/refund.js +110 -45
  490. package/src/lib/server/refund.js.map +1 -1
  491. package/src/lib/server/reserve.js +2 -0
  492. package/src/lib/server/reserve.js.map +1 -1
  493. package/src/lib/server/return-status-action.d.ts +37 -0
  494. package/src/lib/server/return-status-action.js +57 -0
  495. package/src/lib/server/return-status-action.js.map +1 -0
  496. package/src/lib/server/returns.d.ts +119 -0
  497. package/src/lib/server/returns.js +938 -0
  498. package/src/lib/server/returns.js.map +1 -0
  499. package/src/lib/server/shipment-records.d.ts +36 -0
  500. package/src/lib/server/shipment-records.js +289 -0
  501. package/src/lib/server/shipment-records.js.map +1 -0
  502. package/src/lib/server/shipping-connector-gates.d.ts +40 -0
  503. package/src/lib/server/shipping-connector-gates.js +97 -0
  504. package/src/lib/server/shipping-connector-gates.js.map +1 -0
  505. package/src/lib/server/shipping-connectors.d.ts +29 -0
  506. package/src/lib/server/shipping-connectors.js +236 -0
  507. package/src/lib/server/shipping-connectors.js.map +1 -0
  508. package/src/lib/server/shippingeasy.d.ts +238 -0
  509. package/src/lib/server/shippingeasy.js +787 -0
  510. package/src/lib/server/shippingeasy.js.map +1 -0
  511. package/src/lib/server/shipstation.d.ts +129 -0
  512. package/src/lib/server/shipstation.js +483 -0
  513. package/src/lib/server/shipstation.js.map +1 -0
  514. package/src/lib/server/site-page-resolver.d.ts +5 -0
  515. package/src/lib/server/site-page-resolver.js +156 -1
  516. package/src/lib/server/site-page-resolver.js.map +1 -1
  517. package/src/lib/server/stock-levels.d.ts +21 -0
  518. package/src/lib/server/stock-levels.js +263 -0
  519. package/src/lib/server/stock-levels.js.map +1 -0
  520. package/src/lib/server/stripe-refund.d.ts +47 -0
  521. package/src/lib/server/stripe-refund.js +87 -0
  522. package/src/lib/server/stripe-refund.js.map +1 -0
  523. package/src/lib/server/supplier-update.js +46 -5
  524. package/src/lib/server/supplier-update.js.map +1 -1
  525. package/src/lib/server/tax-engine-quote.d.ts +47 -0
  526. package/src/lib/server/tax-engine-quote.js +105 -0
  527. package/src/lib/server/tax-engine-quote.js.map +1 -0
  528. package/src/lib/server.js +138 -2
  529. package/src/lib/server.js.map +1 -1
  530. package/src/lib/site.js +12 -0
  531. package/src/lib/site.js.map +1 -1
  532. package/src/lib/subprocessors.d.ts +26 -0
  533. package/src/lib/subprocessors.js +50 -0
  534. package/src/lib/subprocessors.js.map +1 -0
  535. package/src/lib/tenant-emails.js +461 -3
  536. package/src/lib/tenant-emails.js.map +1 -1
  537. package/src/lib/testing/fake-firestore.d.ts +45 -0
  538. package/src/lib/testing/fake-firestore.js +189 -0
  539. package/src/lib/testing/fake-firestore.js.map +1 -0
  540. package/src/lib/testing/memory-firestore.d.ts +123 -0
  541. package/src/lib/testing/memory-firestore.js +274 -0
  542. package/src/lib/testing/memory-firestore.js.map +1 -0
  543. package/src/lib/testing/pos-ops-harness.d.ts +50 -0
  544. package/src/lib/testing/pos-ops-harness.js +184 -0
  545. package/src/lib/testing/pos-ops-harness.js.map +1 -0
  546. package/src/lib/testing/pos-ops-memory-firestore.d.ts +55 -0
  547. package/src/lib/testing/pos-ops-memory-firestore.js +376 -0
  548. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -0
  549. package/src/lib/transfer/records-transfer.d.ts +11 -1
  550. package/src/lib/transfer/records-transfer.js +127 -5
  551. package/src/lib/transfer/records-transfer.js.map +1 -1
  552. package/src/lib/transfer/records.server.d.ts +9 -2
  553. package/src/lib/transfer/records.server.js +58 -7
  554. package/src/lib/transfer/records.server.js.map +1 -1
  555. package/src/lib/transfer/register-transfer-resources.js +40 -1
  556. package/src/lib/transfer/register-transfer-resources.js.map +1 -1
  557. package/src/lib/transfer/register-transfer-ui.js +4 -1
  558. package/src/lib/transfer/register-transfer-ui.js.map +1 -1
  559. package/src/lib/transfer/shipping-presets.d.ts +23 -0
  560. package/src/lib/transfer/shipping-presets.js +156 -0
  561. package/src/lib/transfer/shipping-presets.js.map +1 -0
  562. package/src/lib/transfer/tracking-transfer.d.ts +101 -0
  563. package/src/lib/transfer/tracking-transfer.js +546 -0
  564. package/src/lib/transfer/tracking-transfer.js.map +1 -0
  565. package/src/lib/transfer/tracking.server.d.ts +37 -0
  566. package/src/lib/transfer/tracking.server.js +393 -0
  567. package/src/lib/transfer/tracking.server.js.map +1 -0
  568. package/src/lib/transfer/transfer-keys.d.ts +2 -1
  569. package/src/lib/transfer/transfer-keys.js +6 -2
  570. package/src/lib/transfer/transfer-keys.js.map +1 -1
  571. package/src/lib/utils/code128.d.ts +37 -0
  572. package/src/lib/utils/code128.js +199 -0
  573. package/src/lib/utils/code128.js.map +1 -0
  574. package/src/lib/utils/order-invoice.d.ts +55 -0
  575. package/src/lib/utils/order-invoice.js +127 -0
  576. package/src/lib/utils/order-invoice.js.map +1 -0
  577. package/src/lib/utils/use-checkout-return-notice.d.ts +34 -0
  578. package/src/lib/utils/use-checkout-return-notice.js +78 -0
  579. package/src/lib/utils/use-checkout-return-notice.js.map +1 -0
  580. package/src/lib/server/feed.js +0 -69
  581. package/src/lib/server/feed.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/fulfill-order.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 CommerceModel from '../model'\nimport { createResourceUid, type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\n\n/**\n * The two fulfilment-side transitions, and ONLY those.\n *\n * `cancelled` releases stock under its own transaction and `refunded` moves\n * money under another, so neither belongs to a write whose contract is \"a\n * forward status flip plus a timeline entry, no stock moved, no money moved\".\n * Widening this union is how a caller gets a door around the specifics those\n * routes exist to enforce — the type is the door being shut.\n */\nexport type OrderFulfilmentTarget = 'fulfilled' | 'delivered'\n\nexport interface RecordShipmentRequest {\n /** Site that owns the order. The CALLER has already proven ownership. */\n hostId: string\n orderId: string\n to: OrderFulfilmentTarget\n /** Free text, e.g. `'UPS'`. Bounded by the caller. */\n carrier?: string\n trackingNumber?: string\n}\n\n/**\n * What happened, as a domain fact rather than an HTTP status — each caller\n * maps it into its own error vocabulary (the console route into its JSON\n * shape, `/v1` into the published error envelope), because those two\n * vocabularies are contracts with different audiences and neither may leak\n * into the other.\n *\n * `already` is a SUCCESS and is distinct from `recorded` on purpose: a retried\n * request finds the order in the target status and returns without writing, so\n * a lost response can never append a second copy of the same shipment. A\n * caller that folded the two together would still be correct about the state\n * and would lose the only signal that says \"this was your retry\".\n */\nexport type RecordShipmentOutcome =\n | { outcome: 'recorded' }\n | { outcome: 'already' }\n | { outcome: 'no_such_order' }\n /** The transition rule refused. `from` is the status that refused it. */\n | { outcome: 'blocked'; from: string }\n\n/**\n * Record a shipment — the transaction, with NO authorization of any kind\n * (AGL-2461).\n *\n * This is the whole of what `fulfillOrderHandler` used to do below its auth\n * preamble, lifted out unchanged so a SECOND caller can have it: the customer\n * REST API's `PATCH /v1/sites/{id}/orders/{id}`\n * (`api-v1/orders-and-products.ts`), which authenticates an org API key and\n * so shares not one line of this function's former preamble.\n *\n * Lifted rather than copied, and that is the entire point: a second\n * `ORDER_TRANSITIONS` inside `/v1` would be two tables that drift into the\n * API writing a status the console forbids.\n *\n * **The caller authorizes.** Everything this function knows is the transition\n * rule. It does not know who is asking, and it will happily move any order on\n * any host — `hostId` is taken on trust because its two callers establish\n * trust in ways that have nothing in common (a Firebase uid in `memberRoles`\n * for the console; an org credential that owns the host for `/v1`).\n *\n * Every guarantee AGL-1819 built is inside the transaction and therefore\n * inherited by both callers: `canTransitionOrder` is re-asked under the write\n * so a stale caller cannot skip a state, the already-in-target case returns\n * without writing so a retry cannot append a duplicate shipment, and\n * `lineItemIds` and the timeline are computed from the transaction's OWN read\n * so a note landed from another tab survives.\n */\nexport async function recordOrderShipment({\n hostId,\n orderId,\n to,\n carrier,\n trackingNumber,\n}: RecordShipmentRequest): Promise<RecordShipmentOutcome> {\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = firestore\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n\n return firestore.runTransaction(\n async (transaction): Promise<RecordShipmentOutcome> => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) return { outcome: 'no_such_order' }\n const order = CommerceModel.liftLegacyOrder(\n (snapshot.data() ?? {}) as never,\n )\n // A redelivered click, or the second of two admins. Success because it\n // IS the state the caller asked for — but nothing is written, so a\n // retry cannot append a second copy of the same fulfillment.\n if (order.status === to) return { outcome: 'already' }\n if (!CommerceModel.canTransitionOrder(order.status, to)) {\n return { outcome: 'blocked', from: order.status }\n }\n\n const atMs = Date.now()\n const patch: Record<string, unknown> =\n to === 'fulfilled'\n ? {\n status: 'fulfilled',\n fulfillments: [\n ...(order.fulfillments ?? []),\n {\n id: createResourceUid(),\n lineItemIds: (order.lineItems ?? []).map(\n (_line, index) => index,\n ),\n ...(carrier ? { carrier } : {}),\n ...(trackingNumber ? { trackingNumber } : {}),\n atMs,\n } satisfies CommerceModel.OrderFulfillment,\n ],\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'fulfilled',\n trackingNumber\n ? `${carrier || 'Shipped'} ${trackingNumber}`\n : 'Fulfilled',\n atMs,\n ),\n }\n : {\n status: 'delivered',\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'delivered',\n undefined,\n atMs,\n ),\n }\n transaction.update(orderRef, patch)\n return { outcome: 'recorded' }\n },\n )\n}\n\n/**\n * Fulfil and mark-delivered, with the transition re-asked under the write\n * (AGL-1819) — the last two order-status writes the console made with a client\n * `updateDoc`, moved behind the same shape as `cancel-order.ts`.\n *\n * THE STALE-DIALOG HOLE IS THE SAME ONE AGL-1818 CLOSED FOR CANCEL.\n * `canTransitionOrder` was consulted only to RENDER the buttons, so a dialog\n * opened on a `paid` order that was refunded (or cancelled) in another tab\n * could still write `fulfilled` straight onto it — `ORDER_TRANSITIONS` stayed\n * advisory because nothing consulted it on the way IN. Re-reading the order\n * inside the transaction that writes the status is what turns the table into\n * a guarantee; the race comes back as a 409 naming the state that refused.\n *\n * ONE ROUTE FOR THE TWO FULFILMENT-SIDE TRANSITIONS, and ONLY those. They are\n * the same act — a forward status flip plus a timeline entry, no stock moved,\n * no money moved — so they share a handler parameterized on `to`. It refuses\n * every other target with a 400 on purpose: `cancelled` releases stock under\n * its own transaction (`cancel-order.ts`) and `refunded` moves money\n * (`refund.ts`), so admitting them here would hand callers a door around\n * exactly the specifics those routes exist to enforce.\n *\n * NO STOCK MOVES HERE. The sale decremented inventory when the money landed\n * (see `cancel-order.ts`'s header); shipping the goods changes what is on the\n * shelf not at all. An open `restockCheck` — a partial refund's question,\n * flagged before the merchant ships the rest — survives untouched: the write\n * is an `update()` naming only status, fulfillments and timeline, and the\n * question is still the merchant's to answer.\n *\n * NO NOTIFICATION EITHER, matching the client write this replaces: the\n * merchant fulfilled the order themselves, and `notifyHostManagers` would\n * tell them what they just did. (`supplier-update.ts` notifies because there\n * the SUPPLIER acted and the merchant is the one who needs to hear it.)\n *\n * ONCE. A retried request — a lost response, a second click — finds the order\n * already in the target status and returns success WITHOUT writing: appending\n * a second copy of the same fulfillment is the double this guard exists to\n * stop. It reports `already: true` so the console can say so. A fulfil retried\n * after the order moved on to `delivered` in another tab is a 409 instead,\n * which is the truth: that state cannot be fulfilled (again).\n *\n * THE SERVER'S ORDER, NOT THE DIALOG'S: `lineItemIds` and the timeline append\n * are computed from the transaction's own read, so a note landed from another\n * tab survives — the client write it replaces appended to the dialog's stale\n * copy and dropped it.\n *\n * Role gate: `admin` and `editor`, the role the client write already had\n * under the rules' host catch-all — same reasoning as `cancel-order.ts`.\n */\nexport const fulfillOrderHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body =\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n const hostId = String(body.hostId ?? '')\n const orderId = String(body.orderId ?? '')\n if (!hostId || !orderId) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which would surface as a 500 on a caller's typo rather than the 400 it is.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n const to = String(body.to ?? '') as OrderFulfilmentTarget\n if (to !== 'fulfilled' && to !== 'delivered') {\n // Deliberately NOT a generic transition endpoint — see the header.\n return res.status(400).json({ error: 'to must be fulfilled or delivered' })\n }\n const carrier = String(body.carrier ?? '').slice(0, 40)\n const trackingNumber = String(body.trackingNumber ?? '').slice(0, 60)\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n const memberRole = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (memberRole !== 'admin' && memberRole !== 'editor') {\n return res.status(403).json({ error: 'Not permitted' })\n }\n\n // Authorized above; the shipment itself is the shared transaction. The\n // wire shape below is unchanged — the console dialog branches on `ok`,\n // `already` and the 409's `error` string, and this route's contract is\n // with that dialog, not with the registry's vocabulary.\n const outcome = await recordOrderShipment({\n hostId,\n orderId,\n to,\n carrier,\n trackingNumber,\n })\n if (outcome.outcome === 'no_such_order') {\n return res.status(404).json({ error: 'Unknown order' })\n }\n if (outcome.outcome === 'blocked') {\n return res.status(409).json({\n error:\n to === 'delivered'\n ? `Orders in \"${outcome.from}\" cannot be marked delivered`\n : `Orders in \"${outcome.from}\" cannot be fulfilled`,\n })\n }\n return res\n .status(200)\n .json(\n outcome.outcome === 'already' ? { ok: true, already: true } : { ok: true },\n )\n } catch (error) {\n // Nothing landed — the transaction is all-or-nothing — so the order is\n // still where it was and the merchant can try again.\n console.error('fulfillOrder failed', error)\n return res.status(500).json({\n error: to === 'delivered' ? 'Mark delivered failed' : 'Fulfill failed',\n })\n }\n}\n"],"names":["CommerceModel","createResourceUid","firebaseAdmin","recordOrderShipment","hostId","orderId","to","carrier","trackingNumber","firestore","app","orderRef","collection","doc","runTransaction","transaction","snapshot","order","get","exists","outcome","liftLegacyOrder","data","status","canTransitionOrder","from","atMs","Date","now","patch","fulfillments","id","lineItemIds","lineItems","map","_line","index","timeline","appendOrderEvent","undefined","update","fulfillOrderHandler","req","res","body","method","json","error","authorization","String","headers","idToken","startsWith","slice","length","JSON","parse","test","hostSnapshot","decoded","auth","verifyIdToken","hostRef","memberRole","uid","ok","already","console"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/fulfill-order.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 CommerceModel from '../model'\nimport { announcePluginShipment } from '@aglyn/aglyn/plugin-manager/plugin-shipment-records'\nimport { createResourceUid, type PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { notifyOrderBuyer } from './order-notifications'\nimport { ORDER_DELIVERED_EVENT, ORDER_FULFILLED_EVENT } from '../model/order-events'\nimport { fulfillmentEventView, stageOrderEvent } from './order-events'\nimport { createHash } from 'crypto'\n\n/**\n * The two fulfilment-side transitions, and ONLY those.\n *\n * `cancelled` releases stock under its own transaction and `refunded` moves\n * money under another, so neither belongs to a write whose contract is \"a\n * forward status flip plus a timeline entry, no stock moved, no money moved\".\n * Widening this union is how a caller gets a door around the specifics those\n * routes exist to enforce — the type is the door being shut.\n */\nexport type OrderFulfilmentTarget = 'fulfilled' | 'delivered'\n\n/** How long a carrier name and a tracking number may be, on every door. */\nexport const CARRIER_MAX = 40\nexport const TRACKING_NUMBER_MAX = 60\nconst URL_MAX = 2048\n\nexport interface RecordShipmentRequest {\n /** Site that owns the order. The CALLER has already proven ownership. */\n hostId: string\n orderId: string\n to: OrderFulfilmentTarget\n /** Free text, e.g. `'UPS'`. Bounded by the caller. */\n carrier?: string\n trackingNumber?: string\n /**\n * Which units this shipment covers (AGL-3611). Absent means everything\n * still to ship, which is what a fulfil meant before quantities existed.\n * Ignored for `delivered`.\n */\n lineItems?: ReadonlyArray<{ lineItemId: number; quantity: number }>\n /** An explicit tracking link; without one it is derived from the carrier. */\n trackingUrl?: string\n /** A label a shipping plugin bought for this parcel. */\n labelUrl?: string\n /** That plugin's id for the label (AGL-3612), kept on the fulfillment. */\n labelRef?: string\n /** Whether the buyer is to be told; recorded on the fulfillment. Default on. */\n notify?: boolean\n /**\n * One shipment attempt. A retry carrying the same key finds the fulfillment\n * it already wrote and answers `already`, so a partial shipment, which\n * leaves the order open to more, still cannot be recorded twice.\n */\n idempotencyKey?: string\n /**\n * A shipment whose tracking number an active fulfillment of this order\n * already carries is the same parcel, answered `already` (AGL-3613). For\n * the doors a shipping tool posts to — ShipStation's ShipNotice, a tracking\n * file — where the number is the parcel's identity and the same parcel may\n * have been recorded by hand first.\n */\n onceByTracking?: boolean\n}\n\n/**\n * What happened, as a domain fact rather than an HTTP status — each caller\n * maps it into its own error vocabulary (the console route into its JSON\n * shape, `/v1` into the published error envelope), because those two\n * vocabularies are contracts with different audiences and neither may leak\n * into the other.\n *\n * `already` is a SUCCESS and is distinct from `recorded` on purpose: a retried\n * request finds the order in the target status (or its keyed fulfillment\n * already written) and returns without writing, so a lost response can never\n * append a second copy of the same shipment.\n *\n * `recorded` carries the fulfillment it wrote (absent for `delivered`) and the\n * status the order is now in, so a caller can tell the buyer what shipped.\n */\nexport type RecordShipmentOutcome =\n | {\n outcome: 'recorded'\n status: CommerceModel.OrderStatus\n fulfillment?: CommerceModel.OrderFulfillment\n }\n | { outcome: 'already'; fulfillment?: CommerceModel.OrderFulfillment }\n | { outcome: 'no_such_order' }\n /** The transition rule refused. `from` is the status that refused it. */\n | { outcome: 'blocked'; from: string }\n /** The requested lines or quantities were refused; nothing was written. */\n | { outcome: 'invalid_lines'; problem: CommerceModel.FulfillmentLinesProblem; message: string }\n\n/** Trims a carrier and a tracking number to what every door stores. */\nexport function boundTracking(input: { carrier?: unknown; trackingNumber?: unknown }): {\n carrier: string\n trackingNumber: string\n} {\n return {\n carrier: String(input.carrier ?? '').trim().slice(0, CARRIER_MAX),\n trackingNumber: String(input.trackingNumber ?? '').trim().slice(0, TRACKING_NUMBER_MAX),\n }\n}\n\n/** An https link or nothing: a stored link is rendered to buyers as an anchor. */\nexport function safeHttpsUrl(value: unknown): string | undefined {\n const text = String(value ?? '').trim()\n if (!text || text.length > URL_MAX) return undefined\n try {\n const url = new URL(text)\n return url.protocol === 'https:' ? url.toString() : undefined\n } catch {\n return undefined\n }\n}\n\n/** The fulfillment id a keyed attempt writes, so a retry finds it. */\nexport function fulfillmentIdForKey(orderId: string, key: string): string {\n return `f-${createHash('sha256').update(`${orderId}:${key}`).digest('hex').slice(0, 20)}`\n}\n\n/** The tracking keys a fulfillment stores: the number, the carrier and the link. */\nfunction trackingFields(\n carrier: string,\n trackingNumber: string,\n explicitUrl: string | undefined,\n): Pick<CommerceModel.OrderFulfillment, 'carrier' | 'trackingNumber' | 'trackingUrl'> {\n const trackingUrl =\n explicitUrl ?? (trackingNumber ? CommerceModel.trackingUrlFor(carrier, trackingNumber) ?? undefined : undefined)\n return {\n ...(carrier ? { carrier } : {}),\n ...(trackingNumber ? { trackingNumber } : {}),\n ...(trackingUrl ? { trackingUrl } : {}),\n }\n}\n\n/** The timeline's words for a shipment. */\nfunction shipmentDetail(\n order: CommerceModel.HostOrder,\n lines: readonly CommerceModel.OrderFulfillmentLine[],\n partial: boolean,\n carrier: string,\n trackingNumber: string,\n): string {\n const tracking = trackingNumber ? `${carrier || 'Shipped'} ${trackingNumber}` : ''\n if (!partial) return tracking || 'Fulfilled'\n const what = CommerceModel.describeFulfillmentLines(order, lines)\n return tracking ? `${what} — ${tracking}` : `${what} shipped`\n}\n\nfunction orderRefFor(hostId: string, orderId: string) {\n return firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .doc(orderId)\n}\n\n/**\n * Record a shipment — the transaction, with NO authorization of any kind\n * (AGL-2461).\n *\n * This is the whole of what `fulfillOrderHandler` used to do below its auth\n * preamble, lifted out unchanged so a SECOND caller can have it: the customer\n * REST API's `PATCH /v1/sites/{id}/orders/{id}`\n * (`api-v1/orders-and-products.ts`), which authenticates an org API key and\n * so shares not one line of this function's former preamble.\n *\n * Lifted rather than copied, and that is the entire point: a second\n * `ORDER_TRANSITIONS` inside `/v1` would be two tables that drift into the\n * API writing a status the console forbids.\n *\n * **The caller authorizes.** Everything this function knows is the transition\n * rule. It does not know who is asking, and it will happily move any order on\n * any host — `hostId` is taken on trust because its two callers establish\n * trust in ways that have nothing in common (a Firebase uid in `memberRoles`\n * for the console; an org credential that owns the host for `/v1`).\n *\n * QUANTITIES (AGL-3611). A shipment names units, not just lines, and the\n * remaining count is computed from the transaction's own read, so two admins\n * shipping the last 3 mugs at once cannot ship 6: the second meets\n * `invalid_lines` with `over_fulfilled`. The resulting status is computed\n * from the fulfillments (`statusFromFulfillments`) — `partially_fulfilled`\n * until every shippable unit is covered — and the transition rule is re-asked\n * only when the status actually moves, since a second partial shipment on a\n * `partially_fulfilled` order changes nothing the table speaks to.\n *\n * Every guarantee AGL-1819 built is inside the transaction and therefore\n * inherited by both callers: `canTransitionOrder` is re-asked under the write\n * so a stale caller cannot skip a state, the already-in-target case returns\n * without writing so a retry cannot append a duplicate shipment, and the\n * lines and the timeline are computed from the transaction's OWN read so a\n * note landed from another tab survives.\n */\nexport async function recordOrderShipment(\n request: RecordShipmentRequest,\n): Promise<RecordShipmentOutcome> {\n const { hostId, orderId, to } = request\n const { carrier, trackingNumber } = boundTracking(request)\n const explicitUrl = safeHttpsUrl(request.trackingUrl)\n const labelUrl = safeHttpsUrl(request.labelUrl)\n const firestore = firebaseAdmin.app().firestore()\n const orderRef = orderRefFor(hostId, orderId)\n const keyedId = request.idempotencyKey\n ? fulfillmentIdForKey(orderId, String(request.idempotencyKey).slice(0, 200))\n : null\n\n const result = await firestore.runTransaction(\n async (transaction): Promise<RecordShipmentOutcome> => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) return { outcome: 'no_such_order' }\n const order = CommerceModel.liftLegacyOrder(\n (snapshot.data() ?? {}) as never,\n )\n const atMs = Date.now()\n\n if (to === 'delivered') {\n if (order.status === 'delivered') return { outcome: 'already' }\n if (!CommerceModel.canTransitionOrder(order.status, 'delivered')) {\n return { outcome: 'blocked', from: order.status }\n }\n const delivered = {\n status: 'delivered',\n updatedAtMs: atMs,\n timeline: CommerceModel.appendOrderEvent(order, 'delivered', undefined, atMs),\n }\n transaction.update(orderRef, delivered)\n stageOrderEvent(transaction, ORDER_DELIVERED_EVENT, { hostId, orderId, key: 'delivered', order: { ...snapshot.data(), ...delivered } })\n return { outcome: 'recorded', status: 'delivered' }\n }\n\n // A redelivered keyed attempt: the fulfillment it wrote is there.\n if (keyedId) {\n const existing = (order.fulfillments ?? []).find((entry) => entry.id === keyedId)\n if (existing) return { outcome: 'already', fulfillment: existing }\n }\n if (request.onceByTracking && trackingNumber) {\n const same = CommerceModel.fulfillmentWithTracking(order, trackingNumber)\n if (same) return { outcome: 'already', fulfillment: same }\n }\n const named = (request.lineItems ?? []).length > 0\n // A redelivered click, or the second of two admins, on a \"fulfil\n // everything\". Success because it IS the state the caller asked for —\n // but nothing is written, so a retry cannot append a second copy.\n if (!named && order.status === 'fulfilled') return { outcome: 'already' }\n if (\n order.status !== 'partially_fulfilled' &&\n order.status !== 'fulfilled' &&\n !CommerceModel.canTransitionOrder(order.status, 'partially_fulfilled') &&\n !CommerceModel.canTransitionOrder(order.status, 'fulfilled')\n ) {\n return { outcome: 'blocked', from: order.status }\n }\n\n let lines: CommerceModel.OrderFulfillmentLine[]\n if (named) {\n const resolved = CommerceModel.resolveFulfillmentLines(order, request.lineItems ?? [])\n if (!('lines' in resolved)) {\n return {\n outcome: 'invalid_lines',\n problem: resolved,\n message: CommerceModel.describeFulfillmentLinesProblem(resolved),\n }\n }\n lines = resolved.lines\n } else {\n lines = CommerceModel.remainingFulfillmentLines(order)\n // Nothing physical left: a fulfil closes the digital and service\n // lines instead, which is what it did before quantities existed.\n if (lines.length === 0) {\n lines = CommerceModel.orderLineFulfillmentStates(order)\n .filter((state) => state.remainingQuantity > 0)\n .map((state) => ({ lineItemId: state.lineItemId, quantity: state.remainingQuantity }))\n }\n }\n\n const fulfillment: CommerceModel.OrderFulfillment = {\n id: keyedId ?? createResourceUid(),\n lineItemIds: lines.map((entry) => entry.lineItemId),\n lines,\n ...trackingFields(carrier, trackingNumber, explicitUrl),\n ...(labelUrl ? { labelUrl } : {}),\n ...(request.labelRef ? { labelRef: String(request.labelRef).slice(0, 80) } : {}),\n status: 'active',\n notify: request.notify !== false,\n atMs,\n }\n const fulfillments = [...(order.fulfillments ?? []), fulfillment]\n let status: CommerceModel.OrderStatus = CommerceModel.statusFromFulfillments({\n lineItems: order.lineItems,\n fulfillments,\n })\n // A fulfil with nothing left to cover still closes the order.\n if (status === 'paid') status = 'fulfilled'\n if (status !== order.status && !CommerceModel.canTransitionOrder(order.status, status)) {\n return { outcome: 'blocked', from: order.status }\n }\n const shipped = {\n status,\n fulfillments,\n // What a shipping tool's feed asks (AGL-3613): which orders changed.\n updatedAtMs: atMs,\n timeline: CommerceModel.appendOrderEvent(\n order,\n status,\n shipmentDetail(order, lines, status === 'partially_fulfilled', carrier, trackingNumber),\n atMs,\n ),\n }\n transaction.update(orderRef, shipped)\n // Once per shipment (AGL-3611), in the same write, so the event exists\n // exactly when the shipment does.\n stageOrderEvent(transaction, ORDER_FULFILLED_EVENT, { hostId, orderId, key: fulfillment.id, order: { ...snapshot.data(), ...shipped }, extra: { fulfillment: fulfillmentEventView(order, fulfillment) } })\n return { outcome: 'recorded', status, fulfillment }\n },\n )\n // The BUYER hears about it (AGL-3610): shipped with the tracking link, or\n // delivered. Once per shipment, after the write, and never fails the\n // shipment — see `order-notifications.ts`. A retry returns `already` above\n // and never reaches here. A merchant who unticked \"Notify customer\"\n // (AGL-3611) recorded the shipment with `notify: false`, and nobody is told.\n // Every shipment recorded, by any door, is announced (AGL-3612), so a\n // plugin that follows parcels can follow one typed in by hand too.\n if (result.outcome === 'recorded' && result.fulfillment?.trackingNumber) {\n await announcePluginShipment({\n hostId,\n recordId: orderId,\n shipmentId: result.fulfillment.id,\n ...(result.fulfillment.carrier ? { carrier: result.fulfillment.carrier } : {}),\n trackingNumber: result.fulfillment.trackingNumber,\n ...(request.labelRef ? { labelRef: request.labelRef } : {}),\n })\n }\n if (result.outcome === 'recorded' && result.fulfillment?.notify !== false) {\n await notifyOrderBuyer(\n { hostId, orderId },\n to === 'fulfilled' ? 'shipped' : 'delivered',\n result.fulfillment ? { fulfillmentId: result.fulfillment.id } : {},\n )\n }\n return result\n}\n\n/** What an edit or a cancel of one fulfillment came to. */\nexport type FulfillmentChangeOutcome =\n | { outcome: 'updated'; status: CommerceModel.OrderStatus; fulfillment: CommerceModel.OrderFulfillment }\n | { outcome: 'already'; fulfillment: CommerceModel.OrderFulfillment }\n | { outcome: 'no_such_order' }\n | { outcome: 'no_such_fulfillment' }\n /** The order is history (delivered, refunded, cancelled); `from` names it. */\n | { outcome: 'locked'; from: string }\n\n/**\n * Corrects the tracking on one fulfillment (AGL-3611): a mistyped number, a\n * carrier swapped, a label bought after the parcel was recorded. Moves no\n * status and no stock. A cancelled fulfillment is history and is refused.\n */\nexport async function updateFulfillmentTracking(request: {\n hostId: string\n orderId: string\n fulfillmentId: string\n carrier?: string\n trackingNumber?: string\n trackingUrl?: string\n}): Promise<FulfillmentChangeOutcome> {\n const { carrier, trackingNumber } = boundTracking(request)\n const explicitUrl = safeHttpsUrl(request.trackingUrl)\n const orderRef = orderRefFor(request.hostId, request.orderId)\n return firebaseAdmin\n .app()\n .firestore()\n .runTransaction(async (transaction): Promise<FulfillmentChangeOutcome> => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) return { outcome: 'no_such_order' }\n const order = CommerceModel.liftLegacyOrder((snapshot.data() ?? {}) as never)\n const index = (order.fulfillments ?? []).findIndex((entry) => entry.id === request.fulfillmentId)\n if (index < 0) return { outcome: 'no_such_fulfillment' }\n const current = (order.fulfillments ?? [])[index]\n if (!CommerceModel.fulfillmentIsActive(current) || !['paid', 'partially_fulfilled', 'fulfilled', 'delivered'].includes(order.status)) {\n return { outcome: 'locked', from: CommerceModel.fulfillmentIsActive(current) ? order.status : 'cancelled' }\n }\n const atMs = Date.now()\n const next: CommerceModel.OrderFulfillment = { ...current, updatedAtMs: atMs }\n delete next.carrier\n delete next.trackingNumber\n delete next.trackingUrl\n Object.assign(next, trackingFields(carrier, trackingNumber, explicitUrl))\n if (\n (current.carrier ?? '') === (next.carrier ?? '') &&\n (current.trackingNumber ?? '') === (next.trackingNumber ?? '') &&\n (current.trackingUrl ?? '') === (next.trackingUrl ?? '')\n ) {\n return { outcome: 'already', fulfillment: current }\n }\n const fulfillments = [...(order.fulfillments ?? [])]\n fulfillments[index] = next\n transaction.update(orderRef, {\n fulfillments,\n updatedAtMs: atMs,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'tracking-updated',\n trackingNumber ? `${carrier || 'Tracking'} ${trackingNumber}` : 'Tracking removed',\n atMs,\n ),\n })\n return { outcome: 'updated', status: order.status, fulfillment: next }\n })\n}\n\n/**\n * Cancels one fulfillment (AGL-3611): the parcel was never handed over, or was\n * recorded against the wrong items. Its units go back to unfulfilled and the\n * order's status is recomputed from what remains — `fulfilled` can step back\n * to `partially_fulfilled` or `paid`.\n *\n * That step back is NOT an `ORDER_TRANSITIONS` edge, on purpose: the table\n * says what may happen to an order going forward, and admitting\n * `fulfilled → paid` there would open it to every other caller. This is the one writer\n * that may take it, and only from a status whose fulfillments are still open\n * (`orderFulfillmentsEditable`): a delivered, refunded or cancelled order's\n * shipments are what happened and stay that way.\n */\nexport async function cancelOrderFulfillment(request: {\n hostId: string\n orderId: string\n fulfillmentId: string\n}): Promise<FulfillmentChangeOutcome> {\n const orderRef = orderRefFor(request.hostId, request.orderId)\n return firebaseAdmin\n .app()\n .firestore()\n .runTransaction(async (transaction): Promise<FulfillmentChangeOutcome> => {\n const snapshot = await transaction.get(orderRef)\n if (!snapshot.exists) return { outcome: 'no_such_order' }\n const order = CommerceModel.liftLegacyOrder((snapshot.data() ?? {}) as never)\n const index = (order.fulfillments ?? []).findIndex((entry) => entry.id === request.fulfillmentId)\n if (index < 0) return { outcome: 'no_such_fulfillment' }\n const current = (order.fulfillments ?? [])[index]\n if (!CommerceModel.fulfillmentIsActive(current)) return { outcome: 'already', fulfillment: current }\n if (!CommerceModel.orderFulfillmentsEditable(order)) {\n return { outcome: 'locked', from: order.status }\n }\n const atMs = Date.now()\n const next: CommerceModel.OrderFulfillment = {\n ...current,\n status: 'cancelled',\n cancelledAtMs: atMs,\n updatedAtMs: atMs,\n }\n const fulfillments = [...(order.fulfillments ?? [])]\n fulfillments[index] = next\n const status = CommerceModel.statusFromFulfillments({ lineItems: order.lineItems, fulfillments })\n transaction.update(orderRef, {\n status,\n fulfillments,\n updatedAtMs: atMs,\n timeline: CommerceModel.appendOrderEvent(\n order,\n 'fulfillment-cancelled',\n CommerceModel.describeFulfillmentLines(order, CommerceModel.fulfillmentLineQuantities(order, current)) +\n ' back to unfulfilled',\n atMs,\n ),\n })\n return { outcome: 'updated', status, fulfillment: next }\n })\n}\n\n/**\n * Fulfil and mark-delivered, with the transition re-asked under the write\n * (AGL-1819) — the last two order-status writes the console made with a client\n * `updateDoc`, moved behind the same shape as `cancel-order.ts`.\n *\n * THE STALE-DIALOG HOLE IS THE SAME ONE AGL-1818 CLOSED FOR CANCEL.\n * `canTransitionOrder` was consulted only to RENDER the buttons, so a dialog\n * opened on a `paid` order that was refunded (or cancelled) in another tab\n * could still write `fulfilled` straight onto it — `ORDER_TRANSITIONS` stayed\n * advisory because nothing consulted it on the way IN. Re-reading the order\n * inside the transaction that writes the status is what turns the table into\n * a guarantee; the race comes back as a 409 naming the state that refused.\n *\n * ONE ROUTE FOR THE TWO FULFILMENT-SIDE TRANSITIONS, and ONLY those. They are\n * the same act — a forward status flip plus a timeline entry, no stock moved,\n * no money moved — so they share a handler parameterized on `to`. It refuses\n * every other target with a 400 on purpose: `cancelled` releases stock under\n * its own transaction (`cancel-order.ts`) and `refunded` moves money\n * (`refund.ts`), so admitting them here would hand callers a door around\n * exactly the specifics those routes exist to enforce.\n *\n * NO STOCK MOVES HERE. The sale decremented inventory when the money landed\n * (see `cancel-order.ts`'s header); shipping the goods changes what is on the\n * shelf not at all. An open `restockCheck` — a partial refund's question,\n * flagged before the merchant ships the rest — survives untouched: the write\n * is an `update()` naming only status, fulfillments and timeline, and the\n * question is still the merchant's to answer.\n *\n * NO MANAGER NOTIFICATION, matching the client write this replaces: the\n * merchant fulfilled the order themselves, and `notifyHostManagers` would\n * tell them what they just did. (`supplier-update.ts` notifies because there\n * the SUPPLIER acted and the merchant is the one who needs to hear it.) The\n * BUYER is told, through `recordOrderShipment` (AGL-3610).\n *\n * ONCE. A retried request — a lost response, a second click — finds the order\n * already in the target status and returns success WITHOUT writing: appending\n * a second copy of the same fulfillment is the double this guard exists to\n * stop. It reports `already: true` so the console can say so. A fulfil retried\n * after the order moved on to `delivered` in another tab is a 409 instead,\n * which is the truth: that state cannot be fulfilled (again).\n *\n * THE SERVER'S ORDER, NOT THE DIALOG'S: `lineItemIds` and the timeline append\n * are computed from the transaction's own read, so a note landed from another\n * tab survives — the client write it replaces appended to the dialog's stale\n * copy and dropped it.\n *\n * Role gate: `admin` and `editor`, the role the client write already had\n * under the rules' host catch-all — same reasoning as `cancel-order.ts`.\n */\nexport const fulfillOrderHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const authorization = String(req.headers.authorization ?? '')\n const idToken = authorization.startsWith('Bearer ')\n ? authorization.slice('Bearer '.length)\n : undefined\n if (!idToken) return res.status(401).json({ error: 'Unauthenticated' })\n const body =\n typeof req.body === 'string' ? JSON.parse(req.body) : (req.body ?? {})\n const hostId = String(body.hostId ?? '')\n const orderId = String(body.orderId ?? '')\n if (!hostId || !orderId) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n // Firestore reserves `__…__` ids and `.doc()` throws SYNCHRONOUSLY on one,\n // which would surface as a 500 on a caller's typo rather than the 400 it is.\n if (/^__.*__$/.test(hostId) || /^__.*__$/.test(orderId)) {\n return res.status(400).json({ error: 'Missing hostId or orderId' })\n }\n // Two more acts on one fulfillment (AGL-3611): correct its tracking, or\n // cancel it. Same route, same role gate; neither moves stock or money.\n const action = String(body.action ?? '')\n const fulfillmentId = String(body.fulfillmentId ?? '').slice(0, 100)\n if ((action === 'update-tracking' || action === 'cancel-fulfillment') && !fulfillmentId) {\n return res.status(400).json({ error: 'Missing fulfillmentId' })\n }\n const to = String(body.to ?? '') as OrderFulfilmentTarget\n if (!action && to !== 'fulfilled' && to !== 'delivered') {\n // Deliberately NOT a generic transition endpoint — see the header.\n return res.status(400).json({ error: 'to must be fulfilled or delivered' })\n }\n if (action && action !== 'update-tracking' && action !== 'cancel-fulfillment') {\n return res.status(400).json({ error: 'Unknown action' })\n }\n const { carrier, trackingNumber } = boundTracking(body)\n const lineItems = Array.isArray(body.lineItems)\n ? (body.lineItems as unknown[]).slice(0, 500).map((entry) => ({\n lineItemId: Number((entry as Record<string, unknown>)?.lineItemId),\n quantity: Number((entry as Record<string, unknown>)?.quantity),\n }))\n : undefined\n const idempotencyKey = String(req.headers['idempotency-key'] ?? body.idempotencyKey ?? '').slice(0, 200)\n\n try {\n const decoded = await firebaseAdmin.app().auth().verifyIdToken(idToken)\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n const memberRole = (hostSnapshot.get('memberRoles') ?? {})[decoded.uid]\n if (memberRole !== 'admin' && memberRole !== 'editor') {\n return res.status(403).json({ error: 'Not permitted' })\n }\n\n if (action) {\n const change =\n action === 'update-tracking'\n ? await updateFulfillmentTracking({\n hostId,\n orderId,\n fulfillmentId,\n carrier,\n trackingNumber,\n trackingUrl: body.trackingUrl,\n })\n : await cancelOrderFulfillment({ hostId, orderId, fulfillmentId })\n // A corrected tracking number is a parcel to follow (AGL-3612).\n if (change.outcome === 'updated' && action === 'update-tracking' && change.fulfillment.trackingNumber) {\n await announcePluginShipment({\n hostId,\n recordId: orderId,\n shipmentId: change.fulfillment.id,\n ...(change.fulfillment.carrier ? { carrier: change.fulfillment.carrier } : {}),\n trackingNumber: change.fulfillment.trackingNumber,\n })\n }\n if (change.outcome === 'no_such_order') return res.status(404).json({ error: 'Unknown order' })\n if (change.outcome === 'no_such_fulfillment') {\n return res.status(404).json({ error: 'That shipment is no longer on this order' })\n }\n if (change.outcome === 'locked') {\n return res.status(409).json({\n error:\n change.from === 'cancelled'\n ? 'That shipment was canceled and can no longer be edited'\n : `Shipments on an order in \"${change.from}\" can no longer be changed`,\n })\n }\n return res.status(200).json({\n ok: true,\n ...(change.outcome === 'already' ? { already: true } : { status: change.status }),\n fulfillment: change.fulfillment,\n })\n }\n\n // Authorized above; the shipment itself is the shared transaction. The\n // console dialog branches on `ok`, `already` and the 409's `error`\n // string, and this route's contract is with that dialog, not with the\n // registry's vocabulary.\n const outcome = await recordOrderShipment({\n hostId,\n orderId,\n to,\n carrier,\n trackingNumber,\n ...(lineItems ? { lineItems } : {}),\n ...(body.trackingUrl ? { trackingUrl: String(body.trackingUrl) } : {}),\n ...(body.labelUrl ? { labelUrl: String(body.labelUrl) } : {}),\n ...(body.notify === false ? { notify: false } : {}),\n ...(idempotencyKey ? { idempotencyKey } : {}),\n })\n if (outcome.outcome === 'no_such_order') {\n return res.status(404).json({ error: 'Unknown order' })\n }\n if (outcome.outcome === 'invalid_lines') {\n return res\n .status(outcome.problem.problem === 'over_fulfilled' ? 409 : 400)\n .json({ error: outcome.message })\n }\n if (outcome.outcome === 'blocked') {\n return res.status(409).json({\n error:\n to === 'delivered'\n ? `Orders in \"${outcome.from}\" cannot be marked delivered`\n : `Orders in \"${outcome.from}\" cannot be fulfilled`,\n })\n }\n if (outcome.outcome === 'already') {\n return res.status(200).json({\n ok: true,\n already: true,\n ...(outcome.fulfillment ? { fulfillment: outcome.fulfillment } : {}),\n })\n }\n return res.status(200).json({\n ok: true,\n status: outcome.status,\n ...(outcome.fulfillment ? { fulfillment: outcome.fulfillment } : {}),\n })\n } catch (error) {\n // Nothing landed — the transaction is all-or-nothing — so the order is\n // still where it was and the merchant can try again.\n console.error('fulfillOrder failed', error)\n return res.status(500).json({\n error: to === 'delivered' ? 'Mark delivered failed' : 'Fulfill failed',\n })\n }\n}\n"],"names":["CommerceModel","announcePluginShipment","createResourceUid","firebaseAdmin","notifyOrderBuyer","ORDER_DELIVERED_EVENT","ORDER_FULFILLED_EVENT","fulfillmentEventView","stageOrderEvent","createHash","CARRIER_MAX","TRACKING_NUMBER_MAX","URL_MAX","boundTracking","input","carrier","String","trim","slice","trackingNumber","safeHttpsUrl","value","text","length","undefined","url","URL","protocol","toString","fulfillmentIdForKey","orderId","key","update","digest","trackingFields","explicitUrl","trackingUrl","trackingUrlFor","shipmentDetail","order","lines","partial","tracking","what","describeFulfillmentLines","orderRefFor","hostId","app","firestore","collection","doc","recordOrderShipment","request","result","to","labelUrl","orderRef","keyedId","idempotencyKey","runTransaction","transaction","snapshot","get","exists","outcome","liftLegacyOrder","data","atMs","Date","now","status","canTransitionOrder","from","delivered","updatedAtMs","timeline","appendOrderEvent","existing","fulfillments","find","entry","id","fulfillment","onceByTracking","same","fulfillmentWithTracking","named","lineItems","resolved","resolveFulfillmentLines","problem","message","describeFulfillmentLinesProblem","remainingFulfillmentLines","orderLineFulfillmentStates","filter","state","remainingQuantity","map","lineItemId","quantity","lineItemIds","labelRef","notify","statusFromFulfillments","shipped","extra","recordId","shipmentId","fulfillmentId","updateFulfillmentTracking","current","next","index","findIndex","fulfillmentIsActive","includes","Object","assign","cancelOrderFulfillment","orderFulfillmentsEditable","cancelledAtMs","fulfillmentLineQuantities","fulfillOrderHandler","req","res","body","method","json","error","authorization","headers","idToken","startsWith","JSON","parse","test","action","Array","isArray","Number","hostSnapshot","decoded","auth","verifyIdToken","hostRef","memberRole","uid","change","ok","already","console"],"mappings":"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"}
@@ -0,0 +1,28 @@
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
+ * `GET /api/commerce/feed?hostId=` — the Google Merchant Center feed address
19
+ * this plugin served itself from AGL-299 until AGL-3637, which merchants
20
+ * pasted into Merchant Center as a scheduled fetch.
21
+ *
22
+ * The feed is now written by whichever plugin publishes the catalog to
23
+ * shopping channels, found through core's `core.catalog-feed` contract, so a
24
+ * store that set up its fetch years ago keeps being read. With no publisher
25
+ * registered the address answers 404, which is what it answers once the
26
+ * merchant retires it from the sales channels card.
27
+ */
28
+ export declare function legacyFeedRoute(request: Request): Promise<Response>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { pluginCatalogFeed } from "@aglyn/aglyn/plugin-manager/plugin-product-catalog";
17
+ /**
18
+ * `GET /api/commerce/feed?hostId=` — the Google Merchant Center feed address
19
+ * this plugin served itself from AGL-299 until AGL-3637, which merchants
20
+ * pasted into Merchant Center as a scheduled fetch.
21
+ *
22
+ * The feed is now written by whichever plugin publishes the catalog to
23
+ * shopping channels, found through core's `core.catalog-feed` contract, so a
24
+ * store that set up its fetch years ago keeps being read. With no publisher
25
+ * registered the address answers 404, which is what it answers once the
26
+ * merchant retires it from the sales channels card.
27
+ */ export async function legacyFeedRoute(request) {
28
+ var _searchParams_get;
29
+ const hostId = (_searchParams_get = new URL(request.url).searchParams.get('hostId')) != null ? _searchParams_get : '';
30
+ if (!hostId) {
31
+ return new Response('Missing hostId', {
32
+ status: 400,
33
+ headers: {
34
+ 'Content-Type': 'text/plain; charset=utf-8',
35
+ 'Cache-Control': 'no-store'
36
+ }
37
+ });
38
+ }
39
+ const publisher = pluginCatalogFeed();
40
+ if (!publisher) {
41
+ return new Response('Not found', {
42
+ status: 404,
43
+ headers: {
44
+ 'Content-Type': 'text/plain; charset=utf-8',
45
+ 'Cache-Control': 'no-store'
46
+ }
47
+ });
48
+ }
49
+ return publisher.serveLegacyFeed(request, hostId);
50
+ }
51
+
52
+ //# sourceMappingURL=legacy-feed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/legacy-feed.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 { pluginCatalogFeed } from '@aglyn/aglyn/plugin-manager/plugin-product-catalog'\n\n/**\n * `GET /api/commerce/feed?hostId=` — the Google Merchant Center feed address\n * this plugin served itself from AGL-299 until AGL-3637, which merchants\n * pasted into Merchant Center as a scheduled fetch.\n *\n * The feed is now written by whichever plugin publishes the catalog to\n * shopping channels, found through core's `core.catalog-feed` contract, so a\n * store that set up its fetch years ago keeps being read. With no publisher\n * registered the address answers 404, which is what it answers once the\n * merchant retires it from the sales channels card.\n */\nexport async function legacyFeedRoute(request: Request): Promise<Response> {\n const hostId = new URL(request.url).searchParams.get('hostId') ?? ''\n if (!hostId) {\n return new Response('Missing hostId', {\n status: 400,\n headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-store' },\n })\n }\n const publisher = pluginCatalogFeed()\n if (!publisher) {\n return new Response('Not found', {\n status: 404,\n headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-store' },\n })\n }\n return publisher.serveLegacyFeed(request, hostId)\n}\n"],"names":["pluginCatalogFeed","legacyFeedRoute","request","hostId","URL","url","searchParams","get","Response","status","headers","publisher","serveLegacyFeed"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,iBAAiB,QAAQ,qDAAoD;AAEtF;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,gBAAgBC,OAAgB;QACrC;IAAf,MAAMC,UAAS,oBAAA,IAAIC,IAAIF,QAAQG,GAAG,EAAEC,YAAY,CAACC,GAAG,CAAC,qBAAtC,oBAAmD;IAClE,IAAI,CAACJ,QAAQ;QACX,OAAO,IAAIK,SAAS,kBAAkB;YACpCC,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;gBAA6B,iBAAiB;YAAW;QACtF;IACF;IACA,MAAMC,YAAYX;IAClB,IAAI,CAACW,WAAW;QACd,OAAO,IAAIH,SAAS,aAAa;YAC/BC,QAAQ;YACRC,SAAS;gBAAE,gBAAgB;gBAA6B,iBAAiB;YAAW;QACtF;IACF;IACA,OAAOC,UAAUC,eAAe,CAACV,SAASC;AAC5C"}
@@ -14,6 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ import { type StorefrontCheckoutWallets } from '../model/commerce-payment-methods';
17
18
  /**
18
19
  * The storefront Payment Element (AGL-1944), the half of native payments
19
20
  * AGL-1132 said mattered more: a shopper on a merchant's own domain pays
@@ -76,15 +77,26 @@
76
77
  * reaches a param built here is Clover's switch of new subscriptions to
77
78
  * FLEXIBLE billing mode — so a subscription session pins
78
79
  * `billing_mode[type]=classic` below, and the subscription it creates bills
79
- * exactly as the hosted path's does. The measurement below was taken at
80
- * basil; re-take it in test mode before `release_native_checkout` is turned
81
- * on anywhere.
80
+ * exactly as the hosted path's does.
82
81
  *
83
- * Same probe, same params (line items, a manual tax line,
84
- * `shipping_address_collection`, a `fixed_amount` shipping option, Connect
85
- * `transfer_data[destination]` and `application_fee_amount`), hosted vs custom:
86
- * `amount_total` **6212 in both**. That is the tax-and-shipping parity claim,
87
- * measured rather than assumed.
82
+ * ### Parity, measured (re-taken at dahlia 2026-10-06, AGL-3606)
83
+ *
84
+ * `tools/scripts/measure-native-checkout-parity.mjs` sends the same params
85
+ * twice against Stripe TEST mode on a test connected account — once as the
86
+ * hosted path does, once rewritten by `applyNativeCheckoutParams` with the
87
+ * dahlia pin — and compares `amount_total` and `total_details`:
88
+ *
89
+ * - manual tax line + `fixed_amount` shipping + `application_fee_amount`:
90
+ * **6212 in both** (the basil figure, unchanged);
91
+ * - Stripe Tax (`automatic_tax`) + shipping + fixed `transfer_data[amount]`:
92
+ * **5799 in both**;
93
+ * - Stripe Tax, no shipping: **5000 in both**;
94
+ * - manual tax, no shipping, application fee: **5413 in both**.
95
+ *
96
+ * Stripe Tax's own amount is 0 in both before an address exists and is then
97
+ * computed by Stripe from the address on the SAME session object either way;
98
+ * the in-page form shows it live from `session.total`. Re-run the script after
99
+ * any change to the pinned version.
88
100
  *
89
101
  * ## What this module deliberately does NOT do
90
102
  *
@@ -119,12 +131,12 @@ export interface NativeCheckoutMode {
119
131
  * dead Buy button on every storefront at once. Requiring the key here means the
120
132
  * worst case of a premature flag flip is the redirect we already ship.
121
133
  *
122
- * That is not hypothetical for the storefront. Measured on 2026-08-18 through
123
- * the Vercel REST API (`vercel env ls` cannot see team-shared vars):
124
- * `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` exists as a project-level var on
125
- * `aglyn-console` and is set NOWHERE on `aglyn-tenant`, which is the project
126
- * that serves storefronts. So today this resolves to `native: false` in
127
- * production however the flag is set, and the shopper keeps the redirect.
134
+ * The key is set on `aglyn-tenant`, the Vercel project that serves
135
+ * storefronts, for production, preview and development (added 2026-08-23,
136
+ * which superseded a 2026-08-18 measurement that found it only on
137
+ * `aglyn-console`). Since the release on 2026-10-06 (AGL-3606) the flag is on
138
+ * by default, so every storefront deployment with the key opens the in-page
139
+ * form, and one without it keeps the redirect.
128
140
  *
129
141
  * The org — never the host — is the rollout bucket, per AGL-1656: a hostId and
130
142
  * an orgId hash to different buckets, so bucketing on the host could land a
@@ -162,6 +174,13 @@ export interface NativeCheckoutPayload {
162
174
  publishableKey: string;
163
175
  /** The order document id, and the `session_id` the return URL carries. */
164
176
  sessionId: string;
177
+ /**
178
+ * The wallets the merchant hid (AGL-3629), for the Payment Element's
179
+ * `wallets` option — Stripe will not exclude Apple Pay, Google Pay or Link
180
+ * on the session itself. Absent when nothing is hidden, so a store on the
181
+ * defaults answers exactly what it answered before.
182
+ */
183
+ wallets?: StorefrontCheckoutWallets;
165
184
  }
166
185
  export interface HostedCheckoutPayload {
167
186
  url: string;
@@ -182,4 +201,4 @@ export declare function readCheckoutSessionPayload(session: {
182
201
  url?: string;
183
202
  id?: string;
184
203
  client_secret?: string;
185
- }, mode: NativeCheckoutMode): NativeCheckoutPayload | HostedCheckoutPayload | null;
204
+ }, mode: NativeCheckoutMode, wallets?: StorefrontCheckoutWallets): NativeCheckoutPayload | HostedCheckoutPayload | null;
@@ -1,3 +1,4 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
1
2
  /**
2
3
  * @license
3
4
  * Copyright 2026 Aglyn LLC
@@ -14,6 +15,7 @@
14
15
  * See the License for the specific language governing permissions and
15
16
  * limitations under the License.
16
17
  */ import { isServerReleaseFlagOnForOrg } from "@aglyn/tenant-data-admin";
18
+ import { storefrontWalletsHideAny } from "../model/commerce-payment-methods.js";
17
19
  /**
18
20
  * The storefront Payment Element (AGL-1944), the half of native payments
19
21
  * AGL-1132 said mattered more: a shopper on a merchant's own domain pays
@@ -76,15 +78,26 @@
76
78
  * reaches a param built here is Clover's switch of new subscriptions to
77
79
  * FLEXIBLE billing mode — so a subscription session pins
78
80
  * `billing_mode[type]=classic` below, and the subscription it creates bills
79
- * exactly as the hosted path's does. The measurement below was taken at
80
- * basil; re-take it in test mode before `release_native_checkout` is turned
81
- * on anywhere.
81
+ * exactly as the hosted path's does.
82
82
  *
83
- * Same probe, same params (line items, a manual tax line,
84
- * `shipping_address_collection`, a `fixed_amount` shipping option, Connect
85
- * `transfer_data[destination]` and `application_fee_amount`), hosted vs custom:
86
- * `amount_total` **6212 in both**. That is the tax-and-shipping parity claim,
87
- * measured rather than assumed.
83
+ * ### Parity, measured (re-taken at dahlia 2026-10-06, AGL-3606)
84
+ *
85
+ * `tools/scripts/measure-native-checkout-parity.mjs` sends the same params
86
+ * twice against Stripe TEST mode on a test connected account — once as the
87
+ * hosted path does, once rewritten by `applyNativeCheckoutParams` with the
88
+ * dahlia pin — and compares `amount_total` and `total_details`:
89
+ *
90
+ * - manual tax line + `fixed_amount` shipping + `application_fee_amount`:
91
+ * **6212 in both** (the basil figure, unchanged);
92
+ * - Stripe Tax (`automatic_tax`) + shipping + fixed `transfer_data[amount]`:
93
+ * **5799 in both**;
94
+ * - Stripe Tax, no shipping: **5000 in both**;
95
+ * - manual tax, no shipping, application fee: **5413 in both**.
96
+ *
97
+ * Stripe Tax's own amount is 0 in both before an address exists and is then
98
+ * computed by Stripe from the address on the SAME session object either way;
99
+ * the in-page form shows it live from `session.total`. Re-run the script after
100
+ * any change to the pinned version.
88
101
  *
89
102
  * ## What this module deliberately does NOT do
90
103
  *
@@ -110,12 +123,12 @@
110
123
  * dead Buy button on every storefront at once. Requiring the key here means the
111
124
  * worst case of a premature flag flip is the redirect we already ship.
112
125
  *
113
- * That is not hypothetical for the storefront. Measured on 2026-08-18 through
114
- * the Vercel REST API (`vercel env ls` cannot see team-shared vars):
115
- * `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` exists as a project-level var on
116
- * `aglyn-console` and is set NOWHERE on `aglyn-tenant`, which is the project
117
- * that serves storefronts. So today this resolves to `native: false` in
118
- * production however the flag is set, and the shopper keeps the redirect.
126
+ * The key is set on `aglyn-tenant`, the Vercel project that serves
127
+ * storefronts, for production, preview and development (added 2026-08-23,
128
+ * which superseded a 2026-08-18 measurement that found it only on
129
+ * `aglyn-console`). Since the release on 2026-10-06 (AGL-3606) the flag is on
130
+ * by default, so every storefront deployment with the key opens the in-page
131
+ * form, and one without it keeps the redirect.
119
132
  *
120
133
  * The org — never the host — is the rollout bucket, per AGL-1656: a hostId and
121
134
  * an orgId hash to different buckets, so bucketing on the host could land a
@@ -199,16 +212,18 @@
199
212
  * made every successful session look like a Stripe failure — a 502 to the
200
213
  * shopper, a released claim, and a real Checkout Session left open on the
201
214
  * account. So the check has to move with the mode, and it does.
202
- */ export function readCheckoutSessionPayload(session, mode) {
215
+ */ export function readCheckoutSessionPayload(session, mode, wallets) {
203
216
  if (!mode.native) return (session == null ? void 0 : session.url) ? {
204
217
  url: session.url
205
218
  } : null;
206
219
  if (!(session == null ? void 0 : session.client_secret) || !(session == null ? void 0 : session.id)) return null;
207
- return {
220
+ return _extends({
208
221
  clientSecret: String(session.client_secret),
209
222
  publishableKey: mode.publishableKey,
210
223
  sessionId: String(session.id)
211
- };
224
+ }, wallets && storefrontWalletsHideAny(wallets) ? {
225
+ wallets
226
+ } : {});
212
227
  }
213
228
 
214
229
  //# sourceMappingURL=native-checkout.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/native-checkout.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 { isServerReleaseFlagOnForOrg } from '@aglyn/tenant-data-admin'\n\n/**\n * The storefront Payment Element (AGL-1944), the half of native payments\n * AGL-1132 said mattered more: a shopper on a merchant's own domain pays\n * without being bounced to `checkout.stripe.com` and back.\n *\n * ## Why a Checkout Session and not a bare PaymentIntent\n *\n * AGL-1132 recommended \"PaymentIntent + `<PaymentElement/>`\" for this surface,\n * and AGL-1944 asked for that to be a conscious re-decision rather than an\n * inherited one. It is: the Payment Element ships, the bare PaymentIntent does\n * not, and the difference is worth stating because it is the whole safety\n * argument.\n *\n * A PaymentIntent-backed flow would have to own totals, tax, shipping and the\n * platform fee itself — which means a SECOND place that computes what a shopper\n * owes. Two paths that price a cart independently is how a storefront starts\n * under-collecting tax without anyone noticing: nothing fails, the number is\n * just quietly wrong on one of them. It also emits `payment_intent.succeeded`\n * rather than `checkout.session.completed`, so every fulfilment branch in\n * `billing-webhook.ts` — orders, inventory, coupons, gift cards, licence keys,\n * subscriptions — would need a parallel implementation reading a different\n * object shape.\n *\n * `ui_mode: 'elements'` is the Payment Element backed by a Checkout Session\n * (`'custom'` before the 2026-03-25.dahlia API renamed it). The\n * shopper sees `<PaymentElement/>` inside the merchant's own layout — no Stripe\n * chrome, which is the thing AGL-1944 objected to about embedded Checkout — and\n * the server keeps the session builder it already has. So:\n *\n * - tax, shipping, inventory, coupons, the Connect destination and the fee\n * ladder are the SAME code, not a parallel implementation. Parity is by\n * construction rather than by test;\n * - `checkout.session.completed` still fires, so `billing-webhook.ts` needs\n * no change at all and stays the only thing that fulfils an order.\n *\n * ## The API version, and why it is pinned per-request\n *\n * Measured against live Stripe in test mode: `ui_mode: 'custom'` was refused at\n * the platform account's default API version with\n *\n * Invalid Stripe API version: 2020-08-27. In order to use `ui_mode:\n * custom`, you must upgrade to Stripe API version 2025-03-31.basil.\n *\n * Upgrading the ACCOUNT default would re-version every Stripe call in this\n * repo at once — a change whose blast radius nobody could review in one pass.\n * A `Stripe-Version` header pins one request instead, and the pin is contained\n * in a way worth being explicit about: webhook deliveries are versioned per\n * ENDPOINT, not per request, so the events `billing-webhook.ts` parses keep\n * arriving in exactly the shape it already reads. The only thing read off the\n * pinned response is `client_secret` and `id`, neither of which the version\n * affects.\n *\n * ### Dahlia (AGL-3410)\n *\n * The pin moved from `2025-03-31.basil` to `2026-03-25.dahlia` with the\n * Stripe.js 9 / react-stripe-js 6 upgrade, because the browser half now boots\n * Stripe.js's Dahlia release train, and Dahlia renamed the mode this module\n * sets: `custom` is refused outright and `elements` replaces it. Across the two\n * releases crossed (Clover, Dahlia) the only other Checkout-session break that\n * reaches a param built here is Clover's switch of new subscriptions to\n * FLEXIBLE billing mode — so a subscription session pins\n * `billing_mode[type]=classic` below, and the subscription it creates bills\n * exactly as the hosted path's does. The measurement below was taken at\n * basil; re-take it in test mode before `release_native_checkout` is turned\n * on anywhere.\n *\n * Same probe, same params (line items, a manual tax line,\n * `shipping_address_collection`, a `fixed_amount` shipping option, Connect\n * `transfer_data[destination]` and `application_fee_amount`), hosted vs custom:\n * `amount_total` **6212 in both**. That is the tax-and-shipping parity claim,\n * measured rather than assumed.\n *\n * ## What this module deliberately does NOT do\n *\n * It does not fulfil anything, and it hands the browser nothing it could use to\n * claim an order was paid. The client gets a `clientSecret` — which is an\n * instruction to Stripe, not an assertion about money — and the same\n * `session_id` the redirect flow already put in the return URL. Fulfilment\n * remains `checkout.session.completed` in `billing-webhook.ts`, exactly as with\n * the redirect. An in-page flow makes trusting the browser tempting; the\n * browser is the one participant that can lie about having paid.\n */\n\n/**\n * The API version `ui_mode: 'elements'` needs, pinned on the session-create\n * request only. Stated once so the header and the doc comment cannot drift.\n */\nexport const NATIVE_CHECKOUT_STRIPE_VERSION = '2026-03-25.dahlia'\n\n/** The flag both halves of native checkout share (AGL-1132, AGL-1944). */\nexport const NATIVE_CHECKOUT_FLAG = 'release_native_checkout' as const\n\nexport interface NativeCheckoutMode {\n /** True only when the flag is on for this org AND a publishable key exists. */\n native: boolean\n /** Empty unless `native` — the client needs it to boot Stripe.js. */\n publishableKey: string\n}\n\n/**\n * Two conditions, not one — the same pairing the console's route settled on.\n *\n * A `ui_mode` session returns a `client_secret` and NO `url`, so a browser that\n * cannot mount Stripe.js has nothing to navigate to. If the flag alone decided\n * this, flipping it in an environment without\n * `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` would replace a working redirect with a\n * dead Buy button on every storefront at once. Requiring the key here means the\n * worst case of a premature flag flip is the redirect we already ship.\n *\n * That is not hypothetical for the storefront. Measured on 2026-08-18 through\n * the Vercel REST API (`vercel env ls` cannot see team-shared vars):\n * `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` exists as a project-level var on\n * `aglyn-console` and is set NOWHERE on `aglyn-tenant`, which is the project\n * that serves storefronts. So today this resolves to `native: false` in\n * production however the flag is set, and the shopper keeps the redirect.\n *\n * The org — never the host — is the rollout bucket, per AGL-1656: a hostId and\n * an orgId hash to different buckets, so bucketing on the host could land a\n * merchant's storefront and their console on opposite sides of the same\n * percentage.\n */\nexport async function resolveNativeCheckoutMode(\n orgId: string | null | undefined,\n): Promise<NativeCheckoutMode> {\n const publishableKey = String(\n process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? '',\n ).trim()\n if (!publishableKey) return { native: false, publishableKey: '' }\n // A flag lookup that throws must not take a sale down with it, and the catch\n // is a `try` rather than `.catch()` deliberately: Remote Config being\n // unreachable rejects, but the resolver being absent entirely — an\n // environment where the module never loaded — throws SYNCHRONOUSLY, before\n // there is a promise to attach a handler to. Only the block form covers both.\n // Either way the answer is the same and it is the safe one: the redirect.\n let on: boolean\n try {\n on = await isServerReleaseFlagOnForOrg(NATIVE_CHECKOUT_FLAG, orgId ?? null)\n } catch {\n return { native: false, publishableKey: '' }\n }\n return on ? { native: true, publishableKey } : { native: false, publishableKey: '' }\n}\n\n/**\n * Rewrite a built session param set for the Payment Element, in place.\n *\n * DELETES `success_url` and `cancel_url` rather than leaving them alongside\n * `return_url`: Stripe rejects the pair outright on a `ui_mode` session, and a\n * 400 here would surface to the shopper as \"Checkout failed\" on a store that\n * was working an hour ago. Everything else in the param set — line items, the\n * tax line, `automatic_tax`, shipping options, the Connect destination, the\n * application fee, every `metadata[…]` key the webhook reads — is left exactly\n * as the caller built it. That is the point: this function must be incapable of\n * changing what the shopper is charged.\n *\n * `returnUrl` is the caller's OWN `success_url` string, `{CHECKOUT_SESSION_ID}`\n * placeholder and all. Stripe substitutes it on an embedded-components return\n * exactly as it does on a hosted redirect (measured), so the storefront's\n * post-purchase reporting — which reads `session_id` off the query to name the\n * order it just completed (AGL-1641) — keeps working unchanged.\n */\nexport function applyNativeCheckoutParams(\n params: URLSearchParams,\n returnUrl: string,\n): void {\n params.delete('success_url')\n params.delete('cancel_url')\n params.set('ui_mode', 'elements')\n params.set('return_url', returnUrl)\n // The pinned version defaults a NEW subscription to flexible billing mode\n // (Clover); the hosted path, on the account default, creates classic ones.\n // Stated so both paths bill a subscription the same way.\n if (params.get('mode') === 'subscription') {\n params.set('subscription_data[billing_mode][type]', 'classic')\n }\n}\n\n/**\n * The `Stripe-Version` pin, as headers to spread into the session-create fetch.\n * Empty for the hosted path so its request is byte-identical to today's.\n */\nexport function nativeCheckoutStripeHeaders(\n mode: NativeCheckoutMode,\n): Record<string, string> {\n return mode.native\n ? { 'Stripe-Version': NATIVE_CHECKOUT_STRIPE_VERSION }\n : {}\n}\n\nexport interface NativeCheckoutPayload {\n /** Stripe's own instruction to the browser. Not a claim that money moved. */\n clientSecret: string\n publishableKey: string\n /** The order document id, and the `session_id` the return URL carries. */\n sessionId: string\n}\n\nexport interface HostedCheckoutPayload {\n url: string\n}\n\n/**\n * Read the created session into the payload the storefront gets back.\n *\n * Returns `null` when the session is unusable, which BOTH callers already treat\n * as \"nothing was sold\" — release the idempotency claim and answer 502. The\n * null case is the whole reason this is a function rather than a ternary: the\n * hosted path's liveness check was `!session.url`, and a `ui_mode` session\n * never has one. Left unchanged, switching a store to native mode would have\n * made every successful session look like a Stripe failure — a 502 to the\n * shopper, a released claim, and a real Checkout Session left open on the\n * account. So the check has to move with the mode, and it does.\n */\nexport function readCheckoutSessionPayload(\n session: { url?: string; id?: string; client_secret?: string },\n mode: NativeCheckoutMode,\n): NativeCheckoutPayload | HostedCheckoutPayload | null {\n if (!mode.native) return session?.url ? { url: session.url } : null\n if (!session?.client_secret || !session?.id) return null\n return {\n clientSecret: String(session.client_secret),\n publishableKey: mode.publishableKey,\n sessionId: String(session.id),\n }\n}\n"],"names":["isServerReleaseFlagOnForOrg","NATIVE_CHECKOUT_STRIPE_VERSION","NATIVE_CHECKOUT_FLAG","resolveNativeCheckoutMode","orgId","process","publishableKey","String","env","NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY","trim","native","on","applyNativeCheckoutParams","params","returnUrl","delete","set","get","nativeCheckoutStripeHeaders","mode","readCheckoutSessionPayload","session","url","client_secret","id","clientSecret","sessionId"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,2BAA2B,QAAQ,2BAA0B;AAEtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiFC,GAED;;;CAGC,GACD,OAAO,MAAMC,iCAAiC,oBAAmB;AAEjE,wEAAwE,GACxE,OAAO,MAAMC,uBAAuB,0BAAkC;AAStE;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,eAAeC,0BACpBC,KAAgC;QAG9BC;IADF,MAAMC,iBAAiBC,QACrBF,kDAAAA,QAAQG,GAAG,CAACC,kCAAkC,YAA9CJ,kDAAkD,IAClDK,IAAI;IACN,IAAI,CAACJ,gBAAgB,OAAO;QAAEK,QAAQ;QAAOL,gBAAgB;IAAG;IAChE,6EAA6E;IAC7E,sEAAsE;IACtE,mEAAmE;IACnE,2EAA2E;IAC3E,8EAA8E;IAC9E,0EAA0E;IAC1E,IAAIM;IACJ,IAAI;QACFA,KAAK,MAAMZ,4BAA4BE,sBAAsBE,gBAAAA,QAAS;IACxE,EAAE,eAAM;QACN,OAAO;YAAEO,QAAQ;YAAOL,gBAAgB;QAAG;IAC7C;IACA,OAAOM,KAAK;QAAED,QAAQ;QAAML;IAAe,IAAI;QAAEK,QAAQ;QAAOL,gBAAgB;IAAG;AACrF;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASO,0BACdC,MAAuB,EACvBC,SAAiB;IAEjBD,OAAOE,MAAM,CAAC;IACdF,OAAOE,MAAM,CAAC;IACdF,OAAOG,GAAG,CAAC,WAAW;IACtBH,OAAOG,GAAG,CAAC,cAAcF;IACzB,0EAA0E;IAC1E,2EAA2E;IAC3E,yDAAyD;IACzD,IAAID,OAAOI,GAAG,CAAC,YAAY,gBAAgB;QACzCJ,OAAOG,GAAG,CAAC,yCAAyC;IACtD;AACF;AAEA;;;CAGC,GACD,OAAO,SAASE,4BACdC,IAAwB;IAExB,OAAOA,KAAKT,MAAM,GACd;QAAE,kBAAkBV;IAA+B,IACnD,CAAC;AACP;AAcA;;;;;;;;;;;CAWC,GACD,OAAO,SAASoB,2BACdC,OAA8D,EAC9DF,IAAwB;IAExB,IAAI,CAACA,KAAKT,MAAM,EAAE,OAAOW,CAAAA,2BAAAA,QAASC,GAAG,IAAG;QAAEA,KAAKD,QAAQC,GAAG;IAAC,IAAI;IAC/D,IAAI,EAACD,2BAAAA,QAASE,aAAa,KAAI,EAACF,2BAAAA,QAASG,EAAE,GAAE,OAAO;IACpD,OAAO;QACLC,cAAcnB,OAAOe,QAAQE,aAAa;QAC1ClB,gBAAgBc,KAAKd,cAAc;QACnCqB,WAAWpB,OAAOe,QAAQG,EAAE;IAC9B;AACF"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/native-checkout.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 { isServerReleaseFlagOnForOrg } from '@aglyn/tenant-data-admin'\nimport {\n type StorefrontCheckoutWallets,\n storefrontWalletsHideAny,\n} from '../model/commerce-payment-methods'\n\n/**\n * The storefront Payment Element (AGL-1944), the half of native payments\n * AGL-1132 said mattered more: a shopper on a merchant's own domain pays\n * without being bounced to `checkout.stripe.com` and back.\n *\n * ## Why a Checkout Session and not a bare PaymentIntent\n *\n * AGL-1132 recommended \"PaymentIntent + `<PaymentElement/>`\" for this surface,\n * and AGL-1944 asked for that to be a conscious re-decision rather than an\n * inherited one. It is: the Payment Element ships, the bare PaymentIntent does\n * not, and the difference is worth stating because it is the whole safety\n * argument.\n *\n * A PaymentIntent-backed flow would have to own totals, tax, shipping and the\n * platform fee itself — which means a SECOND place that computes what a shopper\n * owes. Two paths that price a cart independently is how a storefront starts\n * under-collecting tax without anyone noticing: nothing fails, the number is\n * just quietly wrong on one of them. It also emits `payment_intent.succeeded`\n * rather than `checkout.session.completed`, so every fulfilment branch in\n * `billing-webhook.ts` — orders, inventory, coupons, gift cards, licence keys,\n * subscriptions — would need a parallel implementation reading a different\n * object shape.\n *\n * `ui_mode: 'elements'` is the Payment Element backed by a Checkout Session\n * (`'custom'` before the 2026-03-25.dahlia API renamed it). The\n * shopper sees `<PaymentElement/>` inside the merchant's own layout — no Stripe\n * chrome, which is the thing AGL-1944 objected to about embedded Checkout — and\n * the server keeps the session builder it already has. So:\n *\n * - tax, shipping, inventory, coupons, the Connect destination and the fee\n * ladder are the SAME code, not a parallel implementation. Parity is by\n * construction rather than by test;\n * - `checkout.session.completed` still fires, so `billing-webhook.ts` needs\n * no change at all and stays the only thing that fulfils an order.\n *\n * ## The API version, and why it is pinned per-request\n *\n * Measured against live Stripe in test mode: `ui_mode: 'custom'` was refused at\n * the platform account's default API version with\n *\n * Invalid Stripe API version: 2020-08-27. In order to use `ui_mode:\n * custom`, you must upgrade to Stripe API version 2025-03-31.basil.\n *\n * Upgrading the ACCOUNT default would re-version every Stripe call in this\n * repo at once — a change whose blast radius nobody could review in one pass.\n * A `Stripe-Version` header pins one request instead, and the pin is contained\n * in a way worth being explicit about: webhook deliveries are versioned per\n * ENDPOINT, not per request, so the events `billing-webhook.ts` parses keep\n * arriving in exactly the shape it already reads. The only thing read off the\n * pinned response is `client_secret` and `id`, neither of which the version\n * affects.\n *\n * ### Dahlia (AGL-3410)\n *\n * The pin moved from `2025-03-31.basil` to `2026-03-25.dahlia` with the\n * Stripe.js 9 / react-stripe-js 6 upgrade, because the browser half now boots\n * Stripe.js's Dahlia release train, and Dahlia renamed the mode this module\n * sets: `custom` is refused outright and `elements` replaces it. Across the two\n * releases crossed (Clover, Dahlia) the only other Checkout-session break that\n * reaches a param built here is Clover's switch of new subscriptions to\n * FLEXIBLE billing mode — so a subscription session pins\n * `billing_mode[type]=classic` below, and the subscription it creates bills\n * exactly as the hosted path's does.\n *\n * ### Parity, measured (re-taken at dahlia 2026-10-06, AGL-3606)\n *\n * `tools/scripts/measure-native-checkout-parity.mjs` sends the same params\n * twice against Stripe TEST mode on a test connected account — once as the\n * hosted path does, once rewritten by `applyNativeCheckoutParams` with the\n * dahlia pin — and compares `amount_total` and `total_details`:\n *\n * - manual tax line + `fixed_amount` shipping + `application_fee_amount`:\n * **6212 in both** (the basil figure, unchanged);\n * - Stripe Tax (`automatic_tax`) + shipping + fixed `transfer_data[amount]`:\n * **5799 in both**;\n * - Stripe Tax, no shipping: **5000 in both**;\n * - manual tax, no shipping, application fee: **5413 in both**.\n *\n * Stripe Tax's own amount is 0 in both before an address exists and is then\n * computed by Stripe from the address on the SAME session object either way;\n * the in-page form shows it live from `session.total`. Re-run the script after\n * any change to the pinned version.\n *\n * ## What this module deliberately does NOT do\n *\n * It does not fulfil anything, and it hands the browser nothing it could use to\n * claim an order was paid. The client gets a `clientSecret` — which is an\n * instruction to Stripe, not an assertion about money — and the same\n * `session_id` the redirect flow already put in the return URL. Fulfilment\n * remains `checkout.session.completed` in `billing-webhook.ts`, exactly as with\n * the redirect. An in-page flow makes trusting the browser tempting; the\n * browser is the one participant that can lie about having paid.\n */\n\n/**\n * The API version `ui_mode: 'elements'` needs, pinned on the session-create\n * request only. Stated once so the header and the doc comment cannot drift.\n */\nexport const NATIVE_CHECKOUT_STRIPE_VERSION = '2026-03-25.dahlia'\n\n/** The flag both halves of native checkout share (AGL-1132, AGL-1944). */\nexport const NATIVE_CHECKOUT_FLAG = 'release_native_checkout' as const\n\nexport interface NativeCheckoutMode {\n /** True only when the flag is on for this org AND a publishable key exists. */\n native: boolean\n /** Empty unless `native` — the client needs it to boot Stripe.js. */\n publishableKey: string\n}\n\n/**\n * Two conditions, not one — the same pairing the console's route settled on.\n *\n * A `ui_mode` session returns a `client_secret` and NO `url`, so a browser that\n * cannot mount Stripe.js has nothing to navigate to. If the flag alone decided\n * this, flipping it in an environment without\n * `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` would replace a working redirect with a\n * dead Buy button on every storefront at once. Requiring the key here means the\n * worst case of a premature flag flip is the redirect we already ship.\n *\n * The key is set on `aglyn-tenant`, the Vercel project that serves\n * storefronts, for production, preview and development (added 2026-08-23,\n * which superseded a 2026-08-18 measurement that found it only on\n * `aglyn-console`). Since the release on 2026-10-06 (AGL-3606) the flag is on\n * by default, so every storefront deployment with the key opens the in-page\n * form, and one without it keeps the redirect.\n *\n * The org — never the host — is the rollout bucket, per AGL-1656: a hostId and\n * an orgId hash to different buckets, so bucketing on the host could land a\n * merchant's storefront and their console on opposite sides of the same\n * percentage.\n */\nexport async function resolveNativeCheckoutMode(\n orgId: string | null | undefined,\n): Promise<NativeCheckoutMode> {\n const publishableKey = String(\n process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? '',\n ).trim()\n if (!publishableKey) return { native: false, publishableKey: '' }\n // A flag lookup that throws must not take a sale down with it, and the catch\n // is a `try` rather than `.catch()` deliberately: Remote Config being\n // unreachable rejects, but the resolver being absent entirely — an\n // environment where the module never loaded — throws SYNCHRONOUSLY, before\n // there is a promise to attach a handler to. Only the block form covers both.\n // Either way the answer is the same and it is the safe one: the redirect.\n let on: boolean\n try {\n on = await isServerReleaseFlagOnForOrg(NATIVE_CHECKOUT_FLAG, orgId ?? null)\n } catch {\n return { native: false, publishableKey: '' }\n }\n return on ? { native: true, publishableKey } : { native: false, publishableKey: '' }\n}\n\n/**\n * Rewrite a built session param set for the Payment Element, in place.\n *\n * DELETES `success_url` and `cancel_url` rather than leaving them alongside\n * `return_url`: Stripe rejects the pair outright on a `ui_mode` session, and a\n * 400 here would surface to the shopper as \"Checkout failed\" on a store that\n * was working an hour ago. Everything else in the param set — line items, the\n * tax line, `automatic_tax`, shipping options, the Connect destination, the\n * application fee, every `metadata[…]` key the webhook reads — is left exactly\n * as the caller built it. That is the point: this function must be incapable of\n * changing what the shopper is charged.\n *\n * `returnUrl` is the caller's OWN `success_url` string, `{CHECKOUT_SESSION_ID}`\n * placeholder and all. Stripe substitutes it on an embedded-components return\n * exactly as it does on a hosted redirect (measured), so the storefront's\n * post-purchase reporting — which reads `session_id` off the query to name the\n * order it just completed (AGL-1641) — keeps working unchanged.\n */\nexport function applyNativeCheckoutParams(\n params: URLSearchParams,\n returnUrl: string,\n): void {\n params.delete('success_url')\n params.delete('cancel_url')\n params.set('ui_mode', 'elements')\n params.set('return_url', returnUrl)\n // The pinned version defaults a NEW subscription to flexible billing mode\n // (Clover); the hosted path, on the account default, creates classic ones.\n // Stated so both paths bill a subscription the same way.\n if (params.get('mode') === 'subscription') {\n params.set('subscription_data[billing_mode][type]', 'classic')\n }\n}\n\n/**\n * The `Stripe-Version` pin, as headers to spread into the session-create fetch.\n * Empty for the hosted path so its request is byte-identical to today's.\n */\nexport function nativeCheckoutStripeHeaders(\n mode: NativeCheckoutMode,\n): Record<string, string> {\n return mode.native\n ? { 'Stripe-Version': NATIVE_CHECKOUT_STRIPE_VERSION }\n : {}\n}\n\nexport interface NativeCheckoutPayload {\n /** Stripe's own instruction to the browser. Not a claim that money moved. */\n clientSecret: string\n publishableKey: string\n /** The order document id, and the `session_id` the return URL carries. */\n sessionId: string\n /**\n * The wallets the merchant hid (AGL-3629), for the Payment Element's\n * `wallets` option — Stripe will not exclude Apple Pay, Google Pay or Link\n * on the session itself. Absent when nothing is hidden, so a store on the\n * defaults answers exactly what it answered before.\n */\n wallets?: StorefrontCheckoutWallets\n}\n\nexport interface HostedCheckoutPayload {\n url: string\n}\n\n/**\n * Read the created session into the payload the storefront gets back.\n *\n * Returns `null` when the session is unusable, which BOTH callers already treat\n * as \"nothing was sold\" — release the idempotency claim and answer 502. The\n * null case is the whole reason this is a function rather than a ternary: the\n * hosted path's liveness check was `!session.url`, and a `ui_mode` session\n * never has one. Left unchanged, switching a store to native mode would have\n * made every successful session look like a Stripe failure — a 502 to the\n * shopper, a released claim, and a real Checkout Session left open on the\n * account. So the check has to move with the mode, and it does.\n */\nexport function readCheckoutSessionPayload(\n session: { url?: string; id?: string; client_secret?: string },\n mode: NativeCheckoutMode,\n wallets?: StorefrontCheckoutWallets,\n): NativeCheckoutPayload | HostedCheckoutPayload | null {\n if (!mode.native) return session?.url ? { url: session.url } : null\n if (!session?.client_secret || !session?.id) return null\n return {\n clientSecret: String(session.client_secret),\n publishableKey: mode.publishableKey,\n sessionId: String(session.id),\n ...(wallets && storefrontWalletsHideAny(wallets) ? { wallets } : {}),\n }\n}\n"],"names":["isServerReleaseFlagOnForOrg","storefrontWalletsHideAny","NATIVE_CHECKOUT_STRIPE_VERSION","NATIVE_CHECKOUT_FLAG","resolveNativeCheckoutMode","orgId","process","publishableKey","String","env","NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY","trim","native","on","applyNativeCheckoutParams","params","returnUrl","delete","set","get","nativeCheckoutStripeHeaders","mode","readCheckoutSessionPayload","session","wallets","url","client_secret","id","clientSecret","sessionId"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,2BAA2B,QAAQ,2BAA0B;AACtE,SAEEC,wBAAwB,QACnB,uCAAmC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FC,GAED;;;CAGC,GACD,OAAO,MAAMC,iCAAiC,oBAAmB;AAEjE,wEAAwE,GACxE,OAAO,MAAMC,uBAAuB,0BAAkC;AAStE;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,eAAeC,0BACpBC,KAAgC;QAG9BC;IADF,MAAMC,iBAAiBC,QACrBF,kDAAAA,QAAQG,GAAG,CAACC,kCAAkC,YAA9CJ,kDAAkD,IAClDK,IAAI;IACN,IAAI,CAACJ,gBAAgB,OAAO;QAAEK,QAAQ;QAAOL,gBAAgB;IAAG;IAChE,6EAA6E;IAC7E,sEAAsE;IACtE,mEAAmE;IACnE,2EAA2E;IAC3E,8EAA8E;IAC9E,0EAA0E;IAC1E,IAAIM;IACJ,IAAI;QACFA,KAAK,MAAMb,4BAA4BG,sBAAsBE,gBAAAA,QAAS;IACxE,EAAE,eAAM;QACN,OAAO;YAAEO,QAAQ;YAAOL,gBAAgB;QAAG;IAC7C;IACA,OAAOM,KAAK;QAAED,QAAQ;QAAML;IAAe,IAAI;QAAEK,QAAQ;QAAOL,gBAAgB;IAAG;AACrF;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASO,0BACdC,MAAuB,EACvBC,SAAiB;IAEjBD,OAAOE,MAAM,CAAC;IACdF,OAAOE,MAAM,CAAC;IACdF,OAAOG,GAAG,CAAC,WAAW;IACtBH,OAAOG,GAAG,CAAC,cAAcF;IACzB,0EAA0E;IAC1E,2EAA2E;IAC3E,yDAAyD;IACzD,IAAID,OAAOI,GAAG,CAAC,YAAY,gBAAgB;QACzCJ,OAAOG,GAAG,CAAC,yCAAyC;IACtD;AACF;AAEA;;;CAGC,GACD,OAAO,SAASE,4BACdC,IAAwB;IAExB,OAAOA,KAAKT,MAAM,GACd;QAAE,kBAAkBV;IAA+B,IACnD,CAAC;AACP;AAqBA;;;;;;;;;;;CAWC,GACD,OAAO,SAASoB,2BACdC,OAA8D,EAC9DF,IAAwB,EACxBG,OAAmC;IAEnC,IAAI,CAACH,KAAKT,MAAM,EAAE,OAAOW,CAAAA,2BAAAA,QAASE,GAAG,IAAG;QAAEA,KAAKF,QAAQE,GAAG;IAAC,IAAI;IAC/D,IAAI,EAACF,2BAAAA,QAASG,aAAa,KAAI,EAACH,2BAAAA,QAASI,EAAE,GAAE,OAAO;IACpD,OAAO;QACLC,cAAcpB,OAAOe,QAAQG,aAAa;QAC1CnB,gBAAgBc,KAAKd,cAAc;QACnCsB,WAAWrB,OAAOe,QAAQI,EAAE;OACxBH,WAAWvB,yBAAyBuB,WAAW;QAAEA;IAAQ,IAAI,CAAC;AAEtE"}
@@ -0,0 +1,23 @@
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
+ * The host event bus, loaded with the first commerce event rather than at
19
+ * boot (AGL-3611): `order-event-triggers.ts` registers from the server
20
+ * declarations, and the runtime it reaches through this module is the
21
+ * automation engine's door, which a boot does not need.
22
+ */
23
+ export declare function emitCommerceHostEvent(hostId: string, type: string, payload: Record<string, string | number | boolean>): Promise<void>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { emitHostEvent } from "@aglyn/tenant-runtime";
17
+ /**
18
+ * The host event bus, loaded with the first commerce event rather than at
19
+ * boot (AGL-3611): `order-event-triggers.ts` registers from the server
20
+ * declarations, and the runtime it reaches through this module is the
21
+ * automation engine's door, which a boot does not need.
22
+ */ export async function emitCommerceHostEvent(hostId, type, payload) {
23
+ await emitHostEvent(hostId, type, payload, {
24
+ actor: {
25
+ kind: 'platform'
26
+ }
27
+ });
28
+ }
29
+
30
+ //# sourceMappingURL=order-event-host-emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/order-event-host-emit.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 { emitHostEvent } from '@aglyn/tenant-runtime'\n\n/**\n * The host event bus, loaded with the first commerce event rather than at\n * boot (AGL-3611): `order-event-triggers.ts` registers from the server\n * declarations, and the runtime it reaches through this module is the\n * automation engine's door, which a boot does not need.\n */\nexport async function emitCommerceHostEvent(\n hostId: string,\n type: string,\n payload: Record<string, string | number | boolean>,\n): Promise<void> {\n await emitHostEvent(hostId, type as never, payload, { actor: { kind: 'platform' } })\n}\n"],"names":["emitHostEvent","emitCommerceHostEvent","hostId","type","payload","actor","kind"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,aAAa,QAAQ,wBAAuB;AAErD;;;;;CAKC,GACD,OAAO,eAAeC,sBACpBC,MAAc,EACdC,IAAY,EACZC,OAAkD;IAElD,MAAMJ,cAAcE,QAAQC,MAAeC,SAAS;QAAEC,OAAO;YAAEC,MAAM;QAAW;IAAE;AACpF"}
@@ -0,0 +1,37 @@
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 PluginDomainEventEnvelope } from '@aglyn/aglyn/plugin-manager/plugin-domain-events';
18
+ /**
19
+ * Commerce's events as workflow triggers (AGL-3611).
20
+ *
21
+ * The workflows plugin listens to host events, flat key/value payloads it
22
+ * puts in an automation's scope. Commerce subscribes to its own order and
23
+ * return events and raises each as the host event its declaration names
24
+ * (`orderPaid`, `orderFulfilled`, …), declared in `plugins.config.json` so
25
+ * every trigger picker lists them. The automation engine is never imported:
26
+ * the host event bus is the seam.
27
+ */
28
+ /** The flat scope an automation reads: the order's facts, then the event's own. */
29
+ export declare function hostEventPayloadFor(envelope: Pick<PluginDomainEventEnvelope, 'event' | 'payload'>): Record<string, string | number | boolean>;
30
+ /**
31
+ * Declares commerce's events and subscribes the trigger bridge, from the
32
+ * server declarations. `emitHostEvent` arrives with the first event, not
33
+ * with the boot.
34
+ */
35
+ export declare function registerCommerceEventTriggers(): void;
36
+ /** The order events that change what ShippingEasy should hold. */
37
+ export declare const SHIPPINGEASY_EVENTS: readonly [import("@aglyn/aglyn/plugin-manager/plugin-domain-events").PluginDomainEvent<import("../model").OrderEventPayload>, import("@aglyn/aglyn/plugin-manager/plugin-domain-events").PluginDomainEvent<import("../model").OrderEventPayload>, import("@aglyn/aglyn/plugin-manager/plugin-domain-events").PluginDomainEvent<import("../model").OrderRefundedEventPayload>];