@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
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/print-queue.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 { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport {\n PRINT_JOB_CLAIM_TIMEOUT_MS,\n PRINT_JOB_DELIVER_WITHIN_MS,\n PRINT_JOB_MAX_ATTEMPTS,\n PRINT_JOB_RETENTION_MS,\n printerColumns,\n type PosPrinter,\n type PrintJob,\n type PrintJobKind,\n type PrintReport,\n} from '../model/commerce-printers'\nimport type { ReceiptData } from '../model/commerce-receipt'\nimport {\n layoutDrawerKick,\n layoutKitchenTicket,\n layoutReceipt,\n layoutReport,\n layoutTestPage,\n type PrintDocument,\n} from '../printing/print-document'\n\n/**\n * The cloud printer job queue (AGL-3619): `hosts/{hostId}/printJobs`.\n *\n * A job is `queued` until its printer takes it, `printing` once it has, and\n * `done` / `failed` / `expired` / `canceled` after. The lifecycle is driven by\n * the PRINTER — it polls, takes, and confirms — so every transition that a\n * second poll could race runs in a Firestore transaction:\n *\n * - taking a job (`claimPrintJob`, `claimNextPrintJob`) moves it to\n * `printing` and counts the attempt. Two polls that arrive together cannot\n * both hand an Epson the same job, because the second transaction re-reads\n * a fresh claim and skips it.\n * - a printer that took a job and never confirmed (power cut, network drop)\n * gets it again after {@link PRINT_JOB_CLAIM_TIMEOUT_MS}, up to\n * {@link PRINT_JOB_MAX_ATTEMPTS} deliveries, then the job fails and the\n * console says so.\n * - nothing is delivered after its `deliverByMs`: a receipt half an hour late\n * is confusing, and a drawer that springs open minutes after the sale that\n * asked for it is cash exposure at an unattended till.\n *\n * Star re-requests the job it was offered (`jobToken`) after an offline spell\n * such as an empty roll, so a `printing` job is offered to its own printer\n * again — Star's GET is idempotent by design. Epson has no GET: the poll\n * response IS the delivery, so Epson only gets a job that nobody holds.\n *\n * The Firestore handle is injected so the transitions are tested against an\n * in-memory store that runs transactions optimistically, as Firestore does.\n */\n\ntype Firestore = any\n\nexport function printJobsRef(firestore: Firestore, hostId: string) {\n return firestore.collection('hosts').doc(hostId).collection('printJobs')\n}\n\nexport function printersRef(firestore: Firestore, hostId: string) {\n return firestore.collection('hosts').doc(hostId).collection('printers')\n}\n\nexport interface EnqueuePrintJobInput {\n kind: PrintJobKind\n receipt?: ReceiptData\n report?: PrintReport\n openDrawer?: boolean\n storeName?: string\n timeZone?: string\n orderId?: string\n registerId?: string\n reason?: string\n createdBy?: string\n /**\n * A deterministic id for a job that must print at most once however often\n * its cause repeats — a sale-completed event delivered twice. A second\n * enqueue under the same id is a no-op.\n */\n jobId?: string\n}\n\n/** Queues one job for one printer; returns its id (the existing one for a repeated `jobId`). */\nexport async function enqueuePrintJob(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n input: EnqueuePrintJobInput,\n nowMs: number = Date.now(),\n): Promise<{ jobId: string; created: boolean }> {\n const collection = printJobsRef(firestore, hostId)\n const ref = input.jobId ? collection.doc(input.jobId) : collection.doc(createResourceUid())\n const job: PrintJob = {\n printerId,\n ...(input.registerId ? { registerId: input.registerId } : {}),\n kind: input.kind,\n status: 'queued',\n ...(input.receipt ? { receipt: input.receipt } : {}),\n ...(input.report ? { report: input.report } : {}),\n ...(input.openDrawer ? { openDrawer: true } : {}),\n ...(input.storeName ? { storeName: input.storeName } : {}),\n ...(input.timeZone ? { timeZone: input.timeZone } : {}),\n ...(input.orderId ? { orderId: input.orderId } : {}),\n ...(input.reason ? { reason: input.reason } : {}),\n ...(input.createdBy ? { createdBy: input.createdBy } : {}),\n attempts: 0,\n createdAtMs: nowMs,\n deliverByMs: nowMs + PRINT_JOB_DELIVER_WITHIN_MS[input.kind],\n expiresAt: new Date(nowMs + PRINT_JOB_RETENTION_MS),\n }\n if (!input.jobId) {\n await ref.set(job)\n return { jobId: ref.id, created: true }\n }\n try {\n await ref.create(job)\n return { jobId: ref.id, created: true }\n } catch (error: any) {\n // ALREADY_EXISTS: the same cause asked twice, and the first one stands.\n if (error?.code === 6 || /already exists/i.test(String(error?.message))) {\n return { jobId: ref.id, created: false }\n }\n throw error\n }\n}\n\ntype Deliverability = 'deliver' | 'skip' | 'expire' | 'fail'\n\n/**\n * What a poll should do with an active job, for the given brand.\n *\n * `skip` is a job someone else (this printer, a moment ago) holds and whose\n * claim is still fresh — Epson must not be handed it twice.\n */\nexport function printJobDeliverability(\n job: PrintJob,\n options: { nowMs: number; reofferHeld: boolean },\n): Deliverability {\n const { nowMs } = options\n if (job.status === 'queued') {\n return nowMs > job.deliverByMs ? 'expire' : 'deliver'\n }\n if (job.status !== 'printing') return 'skip'\n const stale = nowMs - Number(job.claimedAtMs ?? 0) > PRINT_JOB_CLAIM_TIMEOUT_MS\n if (stale && job.attempts >= PRINT_JOB_MAX_ATTEMPTS) return 'fail'\n if (stale) return nowMs > job.deliverByMs ? 'expire' : 'deliver'\n return options.reofferHeld ? 'deliver' : 'skip'\n}\n\nfunction activeJobsQuery(firestore: Firestore, hostId: string, printerId: string) {\n return printJobsRef(firestore, hostId)\n .where('printerId', '==', printerId)\n .where('status', 'in', ['queued', 'printing'])\n .orderBy('createdAtMs', 'asc')\n .limit(10)\n}\n\nfunction closingPatch(outcome: 'expire' | 'fail', nowMs: number): Partial<PrintJob> {\n return outcome === 'expire'\n ? { status: 'expired', finishedAtMs: nowMs, error: 'The printer did not take it in time.' }\n : {\n status: 'failed',\n finishedAtMs: nowMs,\n error: 'The printer took it but never confirmed printing it.',\n }\n}\n\n/**\n * The job a Star printer should be told about on its status POST, without\n * taking it: CloudPRNT's GET does the taking. Jobs past their time are closed\n * on the way.\n */\nexport async function nextPrintJobFor(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n nowMs: number = Date.now(),\n): Promise<{ id: string; job: PrintJob } | null> {\n const snapshot = await activeJobsQuery(firestore, hostId, printerId).get()\n for (const doc of snapshot.docs) {\n const job = doc.data() as PrintJob\n const verdict = printJobDeliverability(job, { nowMs, reofferHeld: true })\n if (verdict === 'deliver') return { id: doc.id, job }\n if (verdict === 'expire' || verdict === 'fail') {\n await closeIfStill(firestore, doc.ref, job.status, closingPatch(verdict, nowMs))\n }\n }\n return null\n}\n\nasync function closeIfStill(\n firestore: Firestore,\n ref: any,\n status: PrintJob['status'],\n patch: Partial<PrintJob>,\n): Promise<void> {\n await firestore.runTransaction(async (transaction: any) => {\n const fresh = await transaction.get(ref)\n if (fresh.exists && fresh.get('status') === status) transaction.update(ref, patch)\n })\n}\n\n/**\n * Takes a named job for its printer (Star's GET with a `jobToken`): moves it\n * to `printing` and counts the attempt. `null` when the job is not this\n * printer's, is finished, or is past its time.\n */\nexport async function claimPrintJob(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n jobId: string,\n nowMs: number = Date.now(),\n): Promise<{ id: string; job: PrintJob } | null> {\n if (!jobId || jobId.includes('/')) return null\n const ref = printJobsRef(firestore, hostId).doc(jobId)\n return firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists) return null\n const job = snapshot.data() as PrintJob\n if (job.printerId !== printerId) return null\n const verdict = printJobDeliverability(job, { nowMs, reofferHeld: true })\n if (verdict === 'expire' || verdict === 'fail') {\n transaction.update(ref, closingPatch(verdict, nowMs))\n return null\n }\n if (verdict !== 'deliver') return null\n // A re-GET of a job this printer already holds (Star retries a download\n // that timed out) is the same delivery, not another attempt.\n const fresh =\n job.status === 'printing' && nowMs - Number(job.claimedAtMs ?? 0) <= PRINT_JOB_CLAIM_TIMEOUT_MS\n const patch: Partial<PrintJob> = fresh\n ? {}\n : { status: 'printing', claimedAtMs: nowMs, attempts: job.attempts + 1 }\n if (!fresh) transaction.update(ref, patch)\n return { id: snapshot.id, job: { ...job, ...patch } }\n })\n}\n\n/**\n * Takes the oldest job nobody holds (Epson's poll, which is the delivery) in\n * one transaction, so two polls that arrive together get different answers.\n */\nexport async function claimNextPrintJob(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n nowMs: number = Date.now(),\n): Promise<{ id: string; job: PrintJob } | null> {\n const query = activeJobsQuery(firestore, hostId, printerId)\n return firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(query)\n let taken: { id: string; job: PrintJob } | null = null\n for (const doc of snapshot.docs) {\n const job = doc.data() as PrintJob\n const verdict = printJobDeliverability(job, { nowMs, reofferHeld: false })\n if (verdict === 'expire' || verdict === 'fail') {\n transaction.update(doc.ref, closingPatch(verdict, nowMs))\n continue\n }\n if (verdict !== 'deliver' || taken) continue\n const patch: Partial<PrintJob> = {\n status: 'printing',\n claimedAtMs: nowMs,\n attempts: job.attempts + 1,\n }\n transaction.update(doc.ref, patch)\n taken = { id: doc.id, job: { ...job, ...patch } }\n }\n return taken\n })\n}\n\n/**\n * Records a printer's result for a job it took. Success closes it; a failure\n * puts it back in the queue until it has used its attempts. Idempotent: a\n * repeated confirmation (Star retries an unanswered DELETE) changes nothing.\n */\nexport async function finishPrintJob(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n jobId: string,\n result: { ok: boolean; code: string },\n nowMs: number = Date.now(),\n): Promise<PrintJob['status'] | null> {\n if (!jobId || jobId.includes('/')) return null\n const ref = printJobsRef(firestore, hostId).doc(jobId)\n return firestore.runTransaction(async (transaction: any) => {\n const snapshot = await transaction.get(ref)\n if (!snapshot.exists) return null\n const job = snapshot.data() as PrintJob\n if (job.printerId !== printerId) return null\n if (job.status !== 'printing' && job.status !== 'queued') return job.status\n const code = String(result.code ?? '').slice(0, 120)\n let patch: Partial<PrintJob>\n if (result.ok) {\n patch = { status: 'done', finishedAtMs: nowMs, resultCode: code }\n } else if (job.attempts >= PRINT_JOB_MAX_ATTEMPTS || nowMs > job.deliverByMs) {\n patch = {\n status: 'failed',\n finishedAtMs: nowMs,\n resultCode: code,\n error: `The printer could not print it (${code || 'no reason given'}).`,\n }\n } else {\n patch = { status: 'queued', resultCode: code }\n }\n transaction.update(ref, patch)\n return patch.status ?? job.status\n })\n}\n\n/** The oldest job a printer holds, for a Star confirmation that carries no `jobToken` (older firmware). */\nexport async function heldPrintJobId(\n firestore: Firestore,\n hostId: string,\n printerId: string,\n): Promise<string | null> {\n const snapshot = await activeJobsQuery(firestore, hostId, printerId).get()\n const held = snapshot.docs.find((doc: any) => doc.get('status') === 'printing')\n return held?.id ?? null\n}\n\n/** The printer-neutral document a job prints, for this printer's paper and logo. */\nexport function printJobDocument(\n job: PrintJob,\n printer: Pick<PosPrinter, 'paperWidthMm' | 'logoKey' | 'name'>,\n): PrintDocument {\n const columns = printerColumns(printer.paperWidthMm)\n const logo = Boolean(printer.logoKey)\n if (job.kind === 'receipt' && job.receipt) {\n return layoutReceipt(job.receipt, { columns, logo, openDrawer: job.openDrawer })\n }\n if (job.kind === 'report' && job.report) {\n return layoutReport(job.report, { columns, logo })\n }\n if (job.kind === 'kitchen' && job.receipt) {\n return layoutKitchenTicket(job.receipt, { columns })\n }\n if (job.kind === 'test') {\n return layoutTestPage({\n columns,\n printerName: printer.name,\n storeName: job.storeName ?? '',\n atMs: job.createdAtMs,\n timeZone: job.timeZone,\n logo,\n openDrawer: job.openDrawer,\n })\n }\n if (job.kind === 'drawer') return layoutDrawerKick(columns)\n // A receipt or ticket with nothing to print prints nothing: falling through\n // to the drawer kick would open a till nobody asked to open.\n return { columns, ops: [] }\n}\n"],"names":["createResourceUid","PRINT_JOB_CLAIM_TIMEOUT_MS","PRINT_JOB_DELIVER_WITHIN_MS","PRINT_JOB_MAX_ATTEMPTS","PRINT_JOB_RETENTION_MS","printerColumns","layoutDrawerKick","layoutKitchenTicket","layoutReceipt","layoutReport","layoutTestPage","printJobsRef","firestore","hostId","collection","doc","printersRef","enqueuePrintJob","printerId","input","nowMs","Date","now","ref","jobId","job","registerId","kind","status","receipt","report","openDrawer","storeName","timeZone","orderId","reason","createdBy","attempts","createdAtMs","deliverByMs","expiresAt","set","id","created","create","error","code","test","String","message","printJobDeliverability","options","stale","Number","claimedAtMs","reofferHeld","activeJobsQuery","where","orderBy","limit","closingPatch","outcome","finishedAtMs","nextPrintJobFor","snapshot","get","docs","data","verdict","closeIfStill","patch","runTransaction","transaction","fresh","exists","update","claimPrintJob","includes","claimNextPrintJob","query","taken","finishPrintJob","result","slice","ok","resultCode","heldPrintJobId","held","find","printJobDocument","printer","columns","paperWidthMm","logo","Boolean","logoKey","printerName","name","atMs","ops"],"mappings":"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"}
@@ -0,0 +1,75 @@
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 PosPrinter, type PrinterBrand, type PrinterState } from '../model/commerce-printers';
18
+ type RouteParams = {
19
+ params: Record<string, string | string[]>;
20
+ };
21
+ export interface ResolvedPrinter {
22
+ hostId: string;
23
+ printerId: string;
24
+ printer: PosPrinter;
25
+ ref: any;
26
+ }
27
+ /** The printer the URL names, when its secret is right and its brand matches the door. */
28
+ export declare function resolvePolledPrinter(context: RouteParams, brand: PrinterBrand, firestore?: any): Promise<ResolvedPrinter | null>;
29
+ /** Writes the printer's status when it changed or the heartbeat is due. */
30
+ export declare function recordPrinterStatus(resolved: ResolvedPrinter, next: {
31
+ state: PrinterState;
32
+ detail?: string;
33
+ pollSeconds?: number;
34
+ }, nowMs: number): Promise<void>;
35
+ /** The media types we serve a Star job in, preferred first. */
36
+ export declare const STAR_JOB_MEDIA_TYPES: readonly ["application/vnd.star.starprntcore", "text/plain"];
37
+ /**
38
+ * The status POST: record what the printer says, and tell it whether a job is
39
+ * waiting. The job is OFFERED (with its id as the `jobToken`), not taken; the
40
+ * printer's GET takes it.
41
+ */
42
+ export declare function handleStarPoll(resolved: ResolvedPrinter, body: Record<string, any>, options?: {
43
+ firestore?: any;
44
+ nowMs?: number;
45
+ allowed?: () => Promise<boolean>;
46
+ }): Promise<Record<string, unknown> | null>;
47
+ /** The job download: take it and render it in the media type the printer chose. */
48
+ export declare function handleStarJobRequest(resolved: ResolvedPrinter, query: URLSearchParams, options?: {
49
+ firestore?: any;
50
+ nowMs?: number;
51
+ allowed?: () => Promise<boolean>;
52
+ }): Promise<{
53
+ contentType: string;
54
+ body: Uint8Array | string;
55
+ } | null>;
56
+ /** The confirmation: `code` 2xx is printed; anything else is a failure to retry or give up on. */
57
+ export declare function handleStarConfirmation(resolved: ResolvedPrinter, query: URLSearchParams, options?: {
58
+ firestore?: any;
59
+ nowMs?: number;
60
+ }): Promise<boolean>;
61
+ /** `/api/commerce/cloudprnt/:hostId/:printerId/:secret` */
62
+ export declare function cloudPrntRoute(request: Request, context: RouteParams): Promise<Response>;
63
+ /**
64
+ * One Epson POST. `GetRequest` is a poll whose answer is the job itself, so
65
+ * the job is TAKEN here; `SetResponse` reports how each job went. Returns the
66
+ * XML to send back, `''` for "nothing to print", or `null` to refuse.
67
+ */
68
+ export declare function handleEpsonPost(resolved: ResolvedPrinter, form: URLSearchParams, options?: {
69
+ firestore?: any;
70
+ nowMs?: number;
71
+ allowed?: () => Promise<boolean>;
72
+ }): Promise<string | null>;
73
+ /** `/api/commerce/epson-sdp/:hostId/:printerId/:secret` */
74
+ export declare function epsonServerDirectPrintRoute(request: Request, context: RouteParams): Promise<Response>;
75
+ export {};
@@ -0,0 +1,325 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ /**
3
+ * @license
4
+ * Copyright 2026 Aglyn LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */ import * as Aglyn from "@aglyn/aglyn/server";
18
+ import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
19
+ import { epsonPrinterState, normalizePrinterDeviceId, starPrinterState } from "../model/commerce-printers.js";
20
+ import { renderEpsonServerDirectPrint, parseEpsonPrintResults } from "../printing/render-epson.js";
21
+ import { renderStar, STAR_MEDIA_TYPE } from "../printing/render-star.js";
22
+ import { renderText } from "../printing/render-text.js";
23
+ import { claimNextPrintJob, claimPrintJob, finishPrintJob, heldPrintJobId, nextPrintJobFor, printersRef, printJobDocument } from "./print-queue.js";
24
+ import { printerSecretMatches } from "./printer-secret.js";
25
+ /**
26
+ * The two doors a cloud receipt printer polls (AGL-3619), registered as
27
+ * MACHINE routes on the console dispatcher: a printer names no member and no
28
+ * site cookie, so the dispatcher's enablement and release gates cannot judge
29
+ * it, and its write limit would refuse a device that polls every few seconds.
30
+ * The route authenticates the printer itself — the per-printer secret in the
31
+ * path and the device identity in the request — and asks the plan before it
32
+ * hands over a job.
33
+ *
34
+ * /api/commerce/cloudprnt/{hostId}/{printerId}/{secret} Star CloudPRNT
35
+ * /api/commerce/epson-sdp/{hostId}/{printerId}/{secret} Epson Server Direct Print
36
+ *
37
+ * Every refusal is a bare 404 that says nothing about which part was wrong.
38
+ */ const NO_STORE = {
39
+ 'Cache-Control': 'no-store, max-age=0',
40
+ Pragma: 'no-cache'
41
+ };
42
+ /** A status write at most this often while nothing changes, so a 5-second poll is not 17,000 writes a day. */ const STATUS_HEARTBEAT_MS = 60 * 1000;
43
+ /** Polls report bodies this small; anything larger is not a printer. */ const MAX_BODY_BYTES = 64 * 1024;
44
+ function param(context, name) {
45
+ var _context_params;
46
+ const value = (_context_params = context.params) == null ? void 0 : _context_params[name];
47
+ return String(Array.isArray(value) ? value[0] : value != null ? value : '');
48
+ }
49
+ const notFound = ()=>new Response(null, {
50
+ status: 404,
51
+ headers: NO_STORE
52
+ });
53
+ /** The printer the URL names, when its secret is right and its brand matches the door. */ export async function resolvePolledPrinter(context, brand, firestore = firebaseAdmin.app().firestore()) {
54
+ const hostId = param(context, 'hostId');
55
+ const printerId = param(context, 'printerId');
56
+ const secret = param(context, 'secret');
57
+ if (!/^[A-Za-z0-9_-]{1,128}$/.test(hostId) || !/^[A-Za-z0-9_-]{1,128}$/.test(printerId)) {
58
+ return null;
59
+ }
60
+ const ref = printersRef(firestore, hostId).doc(printerId);
61
+ const snapshot = await ref.get();
62
+ if (!snapshot.exists) return null;
63
+ const printer = snapshot.data();
64
+ if (printer.brand !== brand) return null;
65
+ if (!printerSecretMatches(hostId, printerId, printer.secretVersion, secret)) return null;
66
+ return {
67
+ hostId,
68
+ printerId,
69
+ printer,
70
+ ref
71
+ };
72
+ }
73
+ /** The device on the wire is the device on the record. */ function deviceMatches(printer, reported) {
74
+ const presented = normalizePrinterDeviceId(printer.brand, reported);
75
+ return Boolean(presented) && presented === printer.deviceId;
76
+ }
77
+ /** May this site's printers be handed work now: the plan still carries POS. */ async function printingAllowed(hostId) {
78
+ try {
79
+ const owner = await getOrgForHost(hostId);
80
+ return Aglyn.checkEntitlement(owner == null ? void 0 : owner.org, 'pos');
81
+ } catch (unused) {
82
+ return false;
83
+ }
84
+ }
85
+ /** Writes the printer's status when it changed or the heartbeat is due. */ export async function recordPrinterStatus(resolved, next, nowMs) {
86
+ var _previous_detail, _next_detail, _ref, _next_pollSeconds, _next_pollSeconds1;
87
+ const previous = resolved.printer.status;
88
+ const changed = !previous || previous.state !== next.state || ((_previous_detail = previous.detail) != null ? _previous_detail : '') !== ((_next_detail = next.detail) != null ? _next_detail : '') || next.pollSeconds !== undefined && previous.pollSeconds !== next.pollSeconds;
89
+ if (!changed && nowMs - Number((_ref = previous == null ? void 0 : previous.atMs) != null ? _ref : 0) < STATUS_HEARTBEAT_MS) return;
90
+ const status = _extends({
91
+ state: next.state,
92
+ atMs: nowMs
93
+ }, next.detail ? {
94
+ detail: next.detail.slice(0, 120)
95
+ } : {}, ((_next_pollSeconds = next.pollSeconds) != null ? _next_pollSeconds : previous == null ? void 0 : previous.pollSeconds) !== undefined ? {
96
+ pollSeconds: (_next_pollSeconds1 = next.pollSeconds) != null ? _next_pollSeconds1 : previous == null ? void 0 : previous.pollSeconds
97
+ } : {});
98
+ await resolved.ref.set({
99
+ status
100
+ }, {
101
+ merge: true
102
+ });
103
+ }
104
+ async function readBody(request) {
105
+ const text = await request.text();
106
+ return text.length > MAX_BODY_BYTES ? '' : text;
107
+ }
108
+ /*==========================================
109
+ * STAR CLOUDPRNT
110
+ *=========================================*/ /** The media types we serve a Star job in, preferred first. */ export const STAR_JOB_MEDIA_TYPES = [
111
+ STAR_MEDIA_TYPE,
112
+ 'text/plain'
113
+ ];
114
+ /**
115
+ * The status POST: record what the printer says, and tell it whether a job is
116
+ * waiting. The job is OFFERED (with its id as the `jobToken`), not taken; the
117
+ * printer's GET takes it.
118
+ */ export async function handleStarPoll(resolved, body, options = {}) {
119
+ var _options_firestore, _options_nowMs, _options_allowed;
120
+ var _actions_find, _resolved_printer_status;
121
+ const firestore = (_options_firestore = options.firestore) != null ? _options_firestore : firebaseAdmin.app().firestore();
122
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
123
+ if (!deviceMatches(resolved.printer, body['printerMAC'])) return null;
124
+ const { state, detail } = starPrinterState(body['statusCode']);
125
+ const actions = Array.isArray(body['clientAction']) ? body['clientAction'] : [];
126
+ const interval = Number((_actions_find = actions.find((action)=>(action == null ? void 0 : action.request) === 'GetPollInterval')) == null ? void 0 : _actions_find.result);
127
+ const pollSeconds = Number.isFinite(interval) && interval > 0 ? Math.round(interval) : undefined;
128
+ await recordPrinterStatus(resolved, {
129
+ state,
130
+ detail,
131
+ pollSeconds
132
+ }, nowMs);
133
+ const next = await nextPrintJobFor(firestore, resolved.hostId, resolved.printerId, nowMs);
134
+ if (next && await ((_options_allowed = options.allowed) != null ? _options_allowed : ()=>printingAllowed(resolved.hostId))()) {
135
+ return {
136
+ jobReady: true,
137
+ mediaTypes: [
138
+ ...STAR_JOB_MEDIA_TYPES
139
+ ],
140
+ jobToken: next.id,
141
+ deleteMethod: 'DELETE'
142
+ };
143
+ }
144
+ // Ask once how often it polls, so the console can say when it will next
145
+ // look. A client action and a job are never sent together: the printer would
146
+ // answer the action and hold the job until the next poll.
147
+ if (((_resolved_printer_status = resolved.printer.status) == null ? void 0 : _resolved_printer_status.pollSeconds) === undefined && pollSeconds === undefined) {
148
+ return {
149
+ jobReady: false,
150
+ clientAction: [
151
+ {
152
+ request: 'GetPollInterval',
153
+ options: ''
154
+ }
155
+ ]
156
+ };
157
+ }
158
+ return {
159
+ jobReady: false
160
+ };
161
+ }
162
+ /** The job download: take it and render it in the media type the printer chose. */ export async function handleStarJobRequest(resolved, query, options = {}) {
163
+ var _options_firestore, _options_nowMs, _options_allowed, _query_get, _query_get1;
164
+ const firestore = (_options_firestore = options.firestore) != null ? _options_firestore : firebaseAdmin.app().firestore();
165
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
166
+ if (!deviceMatches(resolved.printer, query.get('mac'))) return null;
167
+ if (!await ((_options_allowed = options.allowed) != null ? _options_allowed : ()=>printingAllowed(resolved.hostId))()) return null;
168
+ let jobId = (_query_get = query.get('token')) != null ? _query_get : '';
169
+ if (!jobId) {
170
+ var _ref;
171
+ const next = await nextPrintJobFor(firestore, resolved.hostId, resolved.printerId, nowMs);
172
+ jobId = (_ref = next == null ? void 0 : next.id) != null ? _ref : '';
173
+ }
174
+ const claimed = await claimPrintJob(firestore, resolved.hostId, resolved.printerId, jobId, nowMs);
175
+ if (!claimed) return null;
176
+ const document = printJobDocument(claimed.job, resolved.printer);
177
+ const type = ((_query_get1 = query.get('type')) != null ? _query_get1 : STAR_MEDIA_TYPE).toLowerCase();
178
+ if (type.startsWith('text/plain')) {
179
+ return {
180
+ contentType: 'text/plain; charset=us-ascii',
181
+ body: renderText(document)
182
+ };
183
+ }
184
+ return {
185
+ contentType: STAR_MEDIA_TYPE,
186
+ body: renderStar(document, {
187
+ logoKey: resolved.printer.logoKey
188
+ })
189
+ };
190
+ }
191
+ /** The confirmation: `code` 2xx is printed; anything else is a failure to retry or give up on. */ export async function handleStarConfirmation(resolved, query, options = {}) {
192
+ var _options_firestore, _options_nowMs, _query_get;
193
+ const firestore = (_options_firestore = options.firestore) != null ? _options_firestore : firebaseAdmin.app().firestore();
194
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
195
+ if (!deviceMatches(resolved.printer, query.get('mac'))) return false;
196
+ const jobId = query.get('token') || await heldPrintJobId(firestore, resolved.hostId, resolved.printerId);
197
+ if (!jobId) return true;
198
+ const code = (_query_get = query.get('code')) != null ? _query_get : '';
199
+ await finishPrintJob(firestore, resolved.hostId, resolved.printerId, jobId, {
200
+ ok: code.trim().startsWith('2'),
201
+ code
202
+ }, nowMs);
203
+ const { state, detail } = starPrinterState(code);
204
+ if (state !== 'online' && state !== 'unknown') {
205
+ await recordPrinterStatus(resolved, {
206
+ state,
207
+ detail
208
+ }, nowMs);
209
+ }
210
+ return true;
211
+ }
212
+ /** `/api/commerce/cloudprnt/:hostId/:printerId/:secret` */ export async function cloudPrntRoute(request, context) {
213
+ const resolved = await resolvePolledPrinter(context, 'star');
214
+ if (!resolved) return notFound();
215
+ const query = new URL(request.url).searchParams;
216
+ const method = request.method.toUpperCase();
217
+ if (method === 'POST') {
218
+ let body;
219
+ try {
220
+ body = JSON.parse(await readBody(request));
221
+ } catch (unused) {
222
+ return notFound();
223
+ }
224
+ const answer = await handleStarPoll(resolved, body != null ? body : {});
225
+ if (!answer) return notFound();
226
+ return Response.json(answer, {
227
+ headers: NO_STORE
228
+ });
229
+ }
230
+ // A server that cannot take DELETE may ask for `deleteMethod: GET`, which
231
+ // arrives as a GET carrying `delete`; this one asks for DELETE, but a
232
+ // printer configured either way is answered.
233
+ if (method === 'DELETE' || method === 'GET' && query.has('delete')) {
234
+ const ok = await handleStarConfirmation(resolved, query);
235
+ return ok ? new Response(null, {
236
+ status: 200,
237
+ headers: NO_STORE
238
+ }) : notFound();
239
+ }
240
+ if (method === 'GET') {
241
+ const job = await handleStarJobRequest(resolved, query);
242
+ if (!job) return notFound();
243
+ const body = typeof job.body === 'string' ? job.body : job.body.buffer.slice(job.body.byteOffset, job.body.byteOffset + job.body.byteLength);
244
+ return new Response(body, {
245
+ status: 200,
246
+ headers: _extends({}, NO_STORE, {
247
+ 'Content-Type': job.contentType
248
+ })
249
+ });
250
+ }
251
+ return new Response(null, {
252
+ status: 405,
253
+ headers: NO_STORE
254
+ });
255
+ }
256
+ /*==========================================
257
+ * EPSON SERVER DIRECT PRINT
258
+ *=========================================*/ /**
259
+ * One Epson POST. `GetRequest` is a poll whose answer is the job itself, so
260
+ * the job is TAKEN here; `SetResponse` reports how each job went. Returns the
261
+ * XML to send back, `''` for "nothing to print", or `null` to refuse.
262
+ */ export async function handleEpsonPost(resolved, form, options = {}) {
263
+ var _options_firestore, _options_nowMs, _form_get;
264
+ const firestore = (_options_firestore = options.firestore) != null ? _options_firestore : firebaseAdmin.app().firestore();
265
+ const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
266
+ if (!deviceMatches(resolved.printer, form.get('ID'))) return null;
267
+ const connection = (_form_get = form.get('ConnectionType')) != null ? _form_get : '';
268
+ if (connection === 'GetRequest') {
269
+ var _options_allowed;
270
+ // A poll says the printer is reachable; what it looks like comes with results.
271
+ const last = resolved.printer.status;
272
+ const state = last && last.state !== 'unknown' && nowMs - last.atMs < 10 * 60 * 1000 ? last.state : 'online';
273
+ await recordPrinterStatus(resolved, {
274
+ state,
275
+ detail: last == null ? void 0 : last.detail
276
+ }, nowMs);
277
+ if (!await ((_options_allowed = options.allowed) != null ? _options_allowed : ()=>printingAllowed(resolved.hostId))()) return '';
278
+ const claimed = await claimNextPrintJob(firestore, resolved.hostId, resolved.printerId, nowMs);
279
+ if (!claimed) return '';
280
+ return renderEpsonServerDirectPrint(printJobDocument(claimed.job, resolved.printer), {
281
+ jobId: claimed.id,
282
+ logoKey: resolved.printer.logoKey
283
+ });
284
+ }
285
+ if (connection === 'SetResponse') {
286
+ var _form_get1;
287
+ const results = parseEpsonPrintResults((_form_get1 = form.get('ResponseFile')) != null ? _form_get1 : '');
288
+ for (const result of results){
289
+ await finishPrintJob(firestore, resolved.hostId, resolved.printerId, result.jobId, {
290
+ ok: result.success,
291
+ code: result.code || (result.success ? 'success' : 'failed')
292
+ }, nowMs);
293
+ }
294
+ const last = results[results.length - 1];
295
+ if (last) {
296
+ const { state, detail } = epsonPrinterState(last);
297
+ await recordPrinterStatus(resolved, {
298
+ state,
299
+ detail
300
+ }, nowMs);
301
+ }
302
+ return '';
303
+ }
304
+ return null;
305
+ }
306
+ /** `/api/commerce/epson-sdp/:hostId/:printerId/:secret` */ export async function epsonServerDirectPrintRoute(request, context) {
307
+ if (request.method.toUpperCase() !== 'POST') {
308
+ return new Response(null, {
309
+ status: 405,
310
+ headers: NO_STORE
311
+ });
312
+ }
313
+ const resolved = await resolvePolledPrinter(context, 'epson');
314
+ if (!resolved) return notFound();
315
+ const answer = await handleEpsonPost(resolved, new URLSearchParams(await readBody(request)));
316
+ if (answer === null) return notFound();
317
+ return new Response(answer, {
318
+ status: 200,
319
+ headers: _extends({}, NO_STORE, {
320
+ 'Content-Type': 'text/xml; charset=utf-8'
321
+ })
322
+ });
323
+ }
324
+
325
+ //# sourceMappingURL=printer-poll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/printer-poll.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as Aglyn from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport {\n epsonPrinterState,\n normalizePrinterDeviceId,\n starPrinterState,\n type PosPrinter,\n type PrinterBrand,\n type PrinterState,\n type PrinterStatus,\n} from '../model/commerce-printers'\nimport { renderEpsonServerDirectPrint, parseEpsonPrintResults } from '../printing/render-epson'\nimport { renderStar, STAR_MEDIA_TYPE } from '../printing/render-star'\nimport { renderText } from '../printing/render-text'\nimport {\n claimNextPrintJob,\n claimPrintJob,\n finishPrintJob,\n heldPrintJobId,\n nextPrintJobFor,\n printersRef,\n printJobDocument,\n} from './print-queue'\nimport { printerSecretMatches } from './printer-secret'\n\n/**\n * The two doors a cloud receipt printer polls (AGL-3619), registered as\n * MACHINE routes on the console dispatcher: a printer names no member and no\n * site cookie, so the dispatcher's enablement and release gates cannot judge\n * it, and its write limit would refuse a device that polls every few seconds.\n * The route authenticates the printer itself — the per-printer secret in the\n * path and the device identity in the request — and asks the plan before it\n * hands over a job.\n *\n * /api/commerce/cloudprnt/{hostId}/{printerId}/{secret} Star CloudPRNT\n * /api/commerce/epson-sdp/{hostId}/{printerId}/{secret} Epson Server Direct Print\n *\n * Every refusal is a bare 404 that says nothing about which part was wrong.\n */\n\nconst NO_STORE = {\n 'Cache-Control': 'no-store, max-age=0',\n Pragma: 'no-cache',\n}\n\n/** A status write at most this often while nothing changes, so a 5-second poll is not 17,000 writes a day. */\nconst STATUS_HEARTBEAT_MS = 60 * 1000\n\n/** Polls report bodies this small; anything larger is not a printer. */\nconst MAX_BODY_BYTES = 64 * 1024\n\ntype RouteParams = { params: Record<string, string | string[]> }\n\nfunction param(context: RouteParams, name: string): string {\n const value = context.params?.[name]\n return String(Array.isArray(value) ? value[0] : (value ?? ''))\n}\n\nconst notFound = () => new Response(null, { status: 404, headers: NO_STORE })\n\nexport interface ResolvedPrinter {\n hostId: string\n printerId: string\n printer: PosPrinter\n ref: any\n}\n\n/** The printer the URL names, when its secret is right and its brand matches the door. */\nexport async function resolvePolledPrinter(\n context: RouteParams,\n brand: PrinterBrand,\n firestore: any = firebaseAdmin.app().firestore(),\n): Promise<ResolvedPrinter | null> {\n const hostId = param(context, 'hostId')\n const printerId = param(context, 'printerId')\n const secret = param(context, 'secret')\n if (!/^[A-Za-z0-9_-]{1,128}$/.test(hostId) || !/^[A-Za-z0-9_-]{1,128}$/.test(printerId)) {\n return null\n }\n const ref = printersRef(firestore, hostId).doc(printerId)\n const snapshot = await ref.get()\n if (!snapshot.exists) return null\n const printer = snapshot.data() as PosPrinter\n if (printer.brand !== brand) return null\n if (!printerSecretMatches(hostId, printerId, printer.secretVersion, secret)) return null\n return { hostId, printerId, printer, ref }\n}\n\n/** The device on the wire is the device on the record. */\nfunction deviceMatches(printer: PosPrinter, reported: unknown): boolean {\n const presented = normalizePrinterDeviceId(printer.brand, reported)\n return Boolean(presented) && presented === printer.deviceId\n}\n\n/** May this site's printers be handed work now: the plan still carries POS. */\nasync function printingAllowed(hostId: string): Promise<boolean> {\n try {\n const owner = await getOrgForHost(hostId)\n return Aglyn.checkEntitlement(owner?.org as any, 'pos')\n } catch {\n return false\n }\n}\n\n/** Writes the printer's status when it changed or the heartbeat is due. */\nexport async function recordPrinterStatus(\n resolved: ResolvedPrinter,\n next: { state: PrinterState; detail?: string; pollSeconds?: number },\n nowMs: number,\n): Promise<void> {\n const previous = resolved.printer.status\n const changed =\n !previous ||\n previous.state !== next.state ||\n (previous.detail ?? '') !== (next.detail ?? '') ||\n (next.pollSeconds !== undefined && previous.pollSeconds !== next.pollSeconds)\n if (!changed && nowMs - Number(previous?.atMs ?? 0) < STATUS_HEARTBEAT_MS) return\n const status: PrinterStatus = {\n state: next.state,\n atMs: nowMs,\n ...(next.detail ? { detail: next.detail.slice(0, 120) } : {}),\n ...((next.pollSeconds ?? previous?.pollSeconds) !== undefined\n ? { pollSeconds: next.pollSeconds ?? previous?.pollSeconds }\n : {}),\n }\n await resolved.ref.set({ status }, { merge: true })\n}\n\nasync function readBody(request: Request): Promise<string> {\n const text = await request.text()\n return text.length > MAX_BODY_BYTES ? '' : text\n}\n\n/*==========================================\n * STAR CLOUDPRNT\n *=========================================*/\n\n/** The media types we serve a Star job in, preferred first. */\nexport const STAR_JOB_MEDIA_TYPES = [STAR_MEDIA_TYPE, 'text/plain'] as const\n\n/**\n * The status POST: record what the printer says, and tell it whether a job is\n * waiting. The job is OFFERED (with its id as the `jobToken`), not taken; the\n * printer's GET takes it.\n */\nexport async function handleStarPoll(\n resolved: ResolvedPrinter,\n body: Record<string, any>,\n options: { firestore?: any; nowMs?: number; allowed?: () => Promise<boolean> } = {},\n): Promise<Record<string, unknown> | null> {\n const firestore = options.firestore ?? firebaseAdmin.app().firestore()\n const nowMs = options.nowMs ?? Date.now()\n if (!deviceMatches(resolved.printer, body['printerMAC'])) return null\n const { state, detail } = starPrinterState(body['statusCode'])\n const actions: any[] = Array.isArray(body['clientAction']) ? body['clientAction'] : []\n const interval = Number(\n actions.find((action) => action?.request === 'GetPollInterval')?.result,\n )\n const pollSeconds = Number.isFinite(interval) && interval > 0 ? Math.round(interval) : undefined\n await recordPrinterStatus(resolved, { state, detail, pollSeconds }, nowMs)\n const next = await nextPrintJobFor(firestore, resolved.hostId, resolved.printerId, nowMs)\n if (next && (await (options.allowed ?? (() => printingAllowed(resolved.hostId)))())) {\n return {\n jobReady: true,\n mediaTypes: [...STAR_JOB_MEDIA_TYPES],\n jobToken: next.id,\n deleteMethod: 'DELETE',\n }\n }\n // Ask once how often it polls, so the console can say when it will next\n // look. A client action and a job are never sent together: the printer would\n // answer the action and hold the job until the next poll.\n if (resolved.printer.status?.pollSeconds === undefined && pollSeconds === undefined) {\n return { jobReady: false, clientAction: [{ request: 'GetPollInterval', options: '' }] }\n }\n return { jobReady: false }\n}\n\n/** The job download: take it and render it in the media type the printer chose. */\nexport async function handleStarJobRequest(\n resolved: ResolvedPrinter,\n query: URLSearchParams,\n options: { firestore?: any; nowMs?: number; allowed?: () => Promise<boolean> } = {},\n): Promise<{ contentType: string; body: Uint8Array | string } | null> {\n const firestore = options.firestore ?? firebaseAdmin.app().firestore()\n const nowMs = options.nowMs ?? Date.now()\n if (!deviceMatches(resolved.printer, query.get('mac'))) return null\n if (!(await (options.allowed ?? (() => printingAllowed(resolved.hostId)))())) return null\n let jobId = query.get('token') ?? ''\n if (!jobId) {\n const next = await nextPrintJobFor(firestore, resolved.hostId, resolved.printerId, nowMs)\n jobId = next?.id ?? ''\n }\n const claimed = await claimPrintJob(firestore, resolved.hostId, resolved.printerId, jobId, nowMs)\n if (!claimed) return null\n const document = printJobDocument(claimed.job, resolved.printer)\n const type = (query.get('type') ?? STAR_MEDIA_TYPE).toLowerCase()\n if (type.startsWith('text/plain')) {\n return { contentType: 'text/plain; charset=us-ascii', body: renderText(document) }\n }\n return {\n contentType: STAR_MEDIA_TYPE,\n body: renderStar(document, { logoKey: resolved.printer.logoKey }),\n }\n}\n\n/** The confirmation: `code` 2xx is printed; anything else is a failure to retry or give up on. */\nexport async function handleStarConfirmation(\n resolved: ResolvedPrinter,\n query: URLSearchParams,\n options: { firestore?: any; nowMs?: number } = {},\n): Promise<boolean> {\n const firestore = options.firestore ?? firebaseAdmin.app().firestore()\n const nowMs = options.nowMs ?? Date.now()\n if (!deviceMatches(resolved.printer, query.get('mac'))) return false\n const jobId =\n query.get('token') || (await heldPrintJobId(firestore, resolved.hostId, resolved.printerId))\n if (!jobId) return true\n const code = query.get('code') ?? ''\n await finishPrintJob(\n firestore,\n resolved.hostId,\n resolved.printerId,\n jobId,\n { ok: code.trim().startsWith('2'), code },\n nowMs,\n )\n const { state, detail } = starPrinterState(code)\n if (state !== 'online' && state !== 'unknown') {\n await recordPrinterStatus(resolved, { state, detail }, nowMs)\n }\n return true\n}\n\n/** `/api/commerce/cloudprnt/:hostId/:printerId/:secret` */\nexport async function cloudPrntRoute(request: Request, context: RouteParams): Promise<Response> {\n const resolved = await resolvePolledPrinter(context, 'star')\n if (!resolved) return notFound()\n const query = new URL(request.url).searchParams\n const method = request.method.toUpperCase()\n if (method === 'POST') {\n let body: Record<string, any>\n try {\n body = JSON.parse(await readBody(request))\n } catch {\n return notFound()\n }\n const answer = await handleStarPoll(resolved, body ?? {})\n if (!answer) return notFound()\n return Response.json(answer, { headers: NO_STORE })\n }\n // A server that cannot take DELETE may ask for `deleteMethod: GET`, which\n // arrives as a GET carrying `delete`; this one asks for DELETE, but a\n // printer configured either way is answered.\n if (method === 'DELETE' || (method === 'GET' && query.has('delete'))) {\n const ok = await handleStarConfirmation(resolved, query)\n return ok ? new Response(null, { status: 200, headers: NO_STORE }) : notFound()\n }\n if (method === 'GET') {\n const job = await handleStarJobRequest(resolved, query)\n if (!job) return notFound()\n const body =\n typeof job.body === 'string'\n ? job.body\n : job.body.buffer.slice(job.body.byteOffset, job.body.byteOffset + job.body.byteLength)\n return new Response(body as BodyInit, {\n status: 200,\n headers: { ...NO_STORE, 'Content-Type': job.contentType },\n })\n }\n return new Response(null, { status: 405, headers: NO_STORE })\n}\n\n/*==========================================\n * EPSON SERVER DIRECT PRINT\n *=========================================*/\n\n/**\n * One Epson POST. `GetRequest` is a poll whose answer is the job itself, so\n * the job is TAKEN here; `SetResponse` reports how each job went. Returns the\n * XML to send back, `''` for \"nothing to print\", or `null` to refuse.\n */\nexport async function handleEpsonPost(\n resolved: ResolvedPrinter,\n form: URLSearchParams,\n options: { firestore?: any; nowMs?: number; allowed?: () => Promise<boolean> } = {},\n): Promise<string | null> {\n const firestore = options.firestore ?? firebaseAdmin.app().firestore()\n const nowMs = options.nowMs ?? Date.now()\n if (!deviceMatches(resolved.printer, form.get('ID'))) return null\n const connection = form.get('ConnectionType') ?? ''\n if (connection === 'GetRequest') {\n // A poll says the printer is reachable; what it looks like comes with results.\n const last = resolved.printer.status\n const state: PrinterState =\n last && last.state !== 'unknown' && nowMs - last.atMs < 10 * 60 * 1000 ? last.state : 'online'\n await recordPrinterStatus(resolved, { state, detail: last?.detail }, nowMs)\n if (!(await (options.allowed ?? (() => printingAllowed(resolved.hostId)))())) return ''\n const claimed = await claimNextPrintJob(firestore, resolved.hostId, resolved.printerId, nowMs)\n if (!claimed) return ''\n return renderEpsonServerDirectPrint(printJobDocument(claimed.job, resolved.printer), {\n jobId: claimed.id,\n logoKey: resolved.printer.logoKey,\n })\n }\n if (connection === 'SetResponse') {\n const results = parseEpsonPrintResults(form.get('ResponseFile') ?? '')\n for (const result of results) {\n await finishPrintJob(\n firestore,\n resolved.hostId,\n resolved.printerId,\n result.jobId,\n { ok: result.success, code: result.code || (result.success ? 'success' : 'failed') },\n nowMs,\n )\n }\n const last = results[results.length - 1]\n if (last) {\n const { state, detail } = epsonPrinterState(last)\n await recordPrinterStatus(resolved, { state, detail }, nowMs)\n }\n return ''\n }\n return null\n}\n\n/** `/api/commerce/epson-sdp/:hostId/:printerId/:secret` */\nexport async function epsonServerDirectPrintRoute(\n request: Request,\n context: RouteParams,\n): Promise<Response> {\n if (request.method.toUpperCase() !== 'POST') {\n return new Response(null, { status: 405, headers: NO_STORE })\n }\n const resolved = await resolvePolledPrinter(context, 'epson')\n if (!resolved) return notFound()\n const answer = await handleEpsonPost(resolved, new URLSearchParams(await readBody(request)))\n if (answer === null) return notFound()\n return new Response(answer, {\n status: 200,\n headers: { ...NO_STORE, 'Content-Type': 'text/xml; charset=utf-8' },\n })\n}\n"],"names":["Aglyn","firebaseAdmin","getOrgForHost","epsonPrinterState","normalizePrinterDeviceId","starPrinterState","renderEpsonServerDirectPrint","parseEpsonPrintResults","renderStar","STAR_MEDIA_TYPE","renderText","claimNextPrintJob","claimPrintJob","finishPrintJob","heldPrintJobId","nextPrintJobFor","printersRef","printJobDocument","printerSecretMatches","NO_STORE","Pragma","STATUS_HEARTBEAT_MS","MAX_BODY_BYTES","param","context","name","value","params","String","Array","isArray","notFound","Response","status","headers","resolvePolledPrinter","brand","firestore","app","hostId","printerId","secret","test","ref","doc","snapshot","get","exists","printer","data","secretVersion","deviceMatches","reported","presented","Boolean","deviceId","printingAllowed","owner","checkEntitlement","org","recordPrinterStatus","resolved","next","nowMs","previous","changed","state","detail","pollSeconds","undefined","Number","atMs","slice","set","merge","readBody","request","text","length","STAR_JOB_MEDIA_TYPES","handleStarPoll","body","options","actions","Date","now","interval","find","action","result","isFinite","Math","round","allowed","jobReady","mediaTypes","jobToken","id","deleteMethod","clientAction","handleStarJobRequest","query","jobId","claimed","document","job","type","toLowerCase","startsWith","contentType","logoKey","handleStarConfirmation","code","ok","trim","cloudPrntRoute","URL","url","searchParams","method","toUpperCase","JSON","parse","answer","json","has","buffer","byteOffset","byteLength","handleEpsonPost","form","connection","last","results","success","epsonServerDirectPrintRoute","URLSearchParams"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,YAAYA,WAAW,sBAAqB;AAC5C,SAASC,aAAa,EAAEC,aAAa,QAAQ,2BAA0B;AACvE,SACEC,iBAAiB,EACjBC,wBAAwB,EACxBC,gBAAgB,QAKX,gCAA4B;AACnC,SAASC,4BAA4B,EAAEC,sBAAsB,QAAQ,8BAA0B;AAC/F,SAASC,UAAU,EAAEC,eAAe,QAAQ,6BAAyB;AACrE,SAASC,UAAU,QAAQ,6BAAyB;AACpD,SACEC,iBAAiB,EACjBC,aAAa,EACbC,cAAc,EACdC,cAAc,EACdC,eAAe,EACfC,WAAW,EACXC,gBAAgB,QACX,mBAAe;AACtB,SAASC,oBAAoB,QAAQ,sBAAkB;AAEvD;;;;;;;;;;;;;CAaC,GAED,MAAMC,WAAW;IACf,iBAAiB;IACjBC,QAAQ;AACV;AAEA,4GAA4G,GAC5G,MAAMC,sBAAsB,KAAK;AAEjC,sEAAsE,GACtE,MAAMC,iBAAiB,KAAK;AAI5B,SAASC,MAAMC,OAAoB,EAAEC,IAAY;QACjCD;IAAd,MAAME,SAAQF,kBAAAA,QAAQG,MAAM,qBAAdH,eAAgB,CAACC,KAAK;IACpC,OAAOG,OAAOC,MAAMC,OAAO,CAACJ,SAASA,KAAK,CAAC,EAAE,GAAIA,gBAAAA,QAAS;AAC5D;AAEA,MAAMK,WAAW,IAAM,IAAIC,SAAS,MAAM;QAAEC,QAAQ;QAAKC,SAASf;IAAS;AAS3E,wFAAwF,GACxF,OAAO,eAAegB,qBACpBX,OAAoB,EACpBY,KAAmB,EACnBC,YAAiBpC,cAAcqC,GAAG,GAAGD,SAAS,EAAE;IAEhD,MAAME,SAAShB,MAAMC,SAAS;IAC9B,MAAMgB,YAAYjB,MAAMC,SAAS;IACjC,MAAMiB,SAASlB,MAAMC,SAAS;IAC9B,IAAI,CAAC,yBAAyBkB,IAAI,CAACH,WAAW,CAAC,yBAAyBG,IAAI,CAACF,YAAY;QACvF,OAAO;IACT;IACA,MAAMG,MAAM3B,YAAYqB,WAAWE,QAAQK,GAAG,CAACJ;IAC/C,MAAMK,WAAW,MAAMF,IAAIG,GAAG;IAC9B,IAAI,CAACD,SAASE,MAAM,EAAE,OAAO;IAC7B,MAAMC,UAAUH,SAASI,IAAI;IAC7B,IAAID,QAAQZ,KAAK,KAAKA,OAAO,OAAO;IACpC,IAAI,CAAClB,qBAAqBqB,QAAQC,WAAWQ,QAAQE,aAAa,EAAET,SAAS,OAAO;IACpF,OAAO;QAAEF;QAAQC;QAAWQ;QAASL;IAAI;AAC3C;AAEA,wDAAwD,GACxD,SAASQ,cAAcH,OAAmB,EAAEI,QAAiB;IAC3D,MAAMC,YAAYjD,yBAAyB4C,QAAQZ,KAAK,EAAEgB;IAC1D,OAAOE,QAAQD,cAAcA,cAAcL,QAAQO,QAAQ;AAC7D;AAEA,6EAA6E,GAC7E,eAAeC,gBAAgBjB,MAAc;IAC3C,IAAI;QACF,MAAMkB,QAAQ,MAAMvD,cAAcqC;QAClC,OAAOvC,MAAM0D,gBAAgB,CAACD,yBAAAA,MAAOE,GAAG,EAAS;IACnD,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA,yEAAyE,GACzE,OAAO,eAAeC,oBACpBC,QAAyB,EACzBC,IAAoE,EACpEC,KAAa;QAMVC,kBAA4BF,oBAOxBA,mBACcA;IAZrB,MAAME,WAAWH,SAASb,OAAO,CAACf,MAAM;IACxC,MAAMgC,UACJ,CAACD,YACDA,SAASE,KAAK,KAAKJ,KAAKI,KAAK,IAC7B,EAACF,mBAAAA,SAASG,MAAM,YAAfH,mBAAmB,UAASF,eAAAA,KAAKK,MAAM,YAAXL,eAAe,OAC3CA,KAAKM,WAAW,KAAKC,aAAaL,SAASI,WAAW,KAAKN,KAAKM,WAAW;IAC9E,IAAI,CAACH,WAAWF,QAAQO,eAAON,4BAAAA,SAAUO,IAAI,mBAAI,KAAKlD,qBAAqB;IAC3E,MAAMY,SAAwB;QAC5BiC,OAAOJ,KAAKI,KAAK;QACjBK,MAAMR;OACFD,KAAKK,MAAM,GAAG;QAAEA,QAAQL,KAAKK,MAAM,CAACK,KAAK,CAAC,GAAG;IAAK,IAAI,CAAC,GACvD,EAACV,oBAAAA,KAAKM,WAAW,YAAhBN,oBAAoBE,4BAAAA,SAAUI,WAAW,MAAMC,YAChD;QAAED,WAAW,GAAEN,qBAAAA,KAAKM,WAAW,YAAhBN,qBAAoBE,4BAAAA,SAAUI,WAAW;IAAC,IACzD,CAAC;IAEP,MAAMP,SAASlB,GAAG,CAAC8B,GAAG,CAAC;QAAExC;IAAO,GAAG;QAAEyC,OAAO;IAAK;AACnD;AAEA,eAAeC,SAASC,OAAgB;IACtC,MAAMC,OAAO,MAAMD,QAAQC,IAAI;IAC/B,OAAOA,KAAKC,MAAM,GAAGxD,iBAAiB,KAAKuD;AAC7C;AAEA;;2CAE2C,GAE3C,6DAA6D,GAC7D,OAAO,MAAME,uBAAuB;IAACtE;IAAiB;CAAa,CAAS;AAE5E;;;;CAIC,GACD,OAAO,eAAeuE,eACpBnB,QAAyB,EACzBoB,IAAyB,EACzBC,UAAiF,CAAC,CAAC;QAEjEA,oBACJA,gBAUMA;QALlBC,eAgBEtB;IAtBJ,MAAMxB,aAAY6C,qBAAAA,QAAQ7C,SAAS,YAAjB6C,qBAAqBjF,cAAcqC,GAAG,GAAGD,SAAS;IACpE,MAAM0B,SAAQmB,iBAAAA,QAAQnB,KAAK,YAAbmB,iBAAiBE,KAAKC,GAAG;IACvC,IAAI,CAAClC,cAAcU,SAASb,OAAO,EAAEiC,IAAI,CAAC,aAAa,GAAG,OAAO;IACjE,MAAM,EAAEf,KAAK,EAAEC,MAAM,EAAE,GAAG9D,iBAAiB4E,IAAI,CAAC,aAAa;IAC7D,MAAME,UAAiBtD,MAAMC,OAAO,CAACmD,IAAI,CAAC,eAAe,IAAIA,IAAI,CAAC,eAAe,GAAG,EAAE;IACtF,MAAMK,WAAWhB,QACfa,gBAAAA,QAAQI,IAAI,CAAC,CAACC,SAAWA,CAAAA,0BAAAA,OAAQZ,OAAO,MAAK,uCAA7CO,cAAiEM,MAAM;IAEzE,MAAMrB,cAAcE,OAAOoB,QAAQ,CAACJ,aAAaA,WAAW,IAAIK,KAAKC,KAAK,CAACN,YAAYjB;IACvF,MAAMT,oBAAoBC,UAAU;QAAEK;QAAOC;QAAQC;IAAY,GAAGL;IACpE,MAAMD,OAAO,MAAM/C,gBAAgBsB,WAAWwB,SAAStB,MAAM,EAAEsB,SAASrB,SAAS,EAAEuB;IACnF,IAAID,QAAS,MAAM,EAACoB,mBAAAA,QAAQW,OAAO,YAAfX,mBAAoB,IAAM1B,gBAAgBK,SAAStB,MAAM,MAAQ;QACnF,OAAO;YACLuD,UAAU;YACVC,YAAY;mBAAIhB;aAAqB;YACrCiB,UAAUlC,KAAKmC,EAAE;YACjBC,cAAc;QAChB;IACF;IACA,wEAAwE;IACxE,6EAA6E;IAC7E,0DAA0D;IAC1D,IAAIrC,EAAAA,2BAAAA,SAASb,OAAO,CAACf,MAAM,qBAAvB4B,yBAAyBO,WAAW,MAAKC,aAAaD,gBAAgBC,WAAW;QACnF,OAAO;YAAEyB,UAAU;YAAOK,cAAc;gBAAC;oBAAEvB,SAAS;oBAAmBM,SAAS;gBAAG;aAAE;QAAC;IACxF;IACA,OAAO;QAAEY,UAAU;IAAM;AAC3B;AAEA,iFAAiF,GACjF,OAAO,eAAeM,qBACpBvC,QAAyB,EACzBwC,KAAsB,EACtBnB,UAAiF,CAAC,CAAC;QAEjEA,oBACJA,gBAEDA,kBACDmB,YAQEA;IAZd,MAAMhE,aAAY6C,qBAAAA,QAAQ7C,SAAS,YAAjB6C,qBAAqBjF,cAAcqC,GAAG,GAAGD,SAAS;IACpE,MAAM0B,SAAQmB,iBAAAA,QAAQnB,KAAK,YAAbmB,iBAAiBE,KAAKC,GAAG;IACvC,IAAI,CAAClC,cAAcU,SAASb,OAAO,EAAEqD,MAAMvD,GAAG,CAAC,SAAS,OAAO;IAC/D,IAAI,CAAE,MAAM,EAACoC,mBAAAA,QAAQW,OAAO,YAAfX,mBAAoB,IAAM1B,gBAAgBK,SAAStB,MAAM,MAAQ,OAAO;IACrF,IAAI+D,SAAQD,aAAAA,MAAMvD,GAAG,CAAC,oBAAVuD,aAAsB;IAClC,IAAI,CAACC,OAAO;;QACV,MAAMxC,OAAO,MAAM/C,gBAAgBsB,WAAWwB,SAAStB,MAAM,EAAEsB,SAASrB,SAAS,EAAEuB;QACnFuC,gBAAQxC,wBAAAA,KAAMmC,EAAE,mBAAI;IACtB;IACA,MAAMM,UAAU,MAAM3F,cAAcyB,WAAWwB,SAAStB,MAAM,EAAEsB,SAASrB,SAAS,EAAE8D,OAAOvC;IAC3F,IAAI,CAACwC,SAAS,OAAO;IACrB,MAAMC,WAAWvF,iBAAiBsF,QAAQE,GAAG,EAAE5C,SAASb,OAAO;IAC/D,MAAM0D,OAAO,EAACL,cAAAA,MAAMvD,GAAG,CAAC,mBAAVuD,cAAqB5F,iBAAiBkG,WAAW;IAC/D,IAAID,KAAKE,UAAU,CAAC,eAAe;QACjC,OAAO;YAAEC,aAAa;YAAgC5B,MAAMvE,WAAW8F;QAAU;IACnF;IACA,OAAO;QACLK,aAAapG;QACbwE,MAAMzE,WAAWgG,UAAU;YAAEM,SAASjD,SAASb,OAAO,CAAC8D,OAAO;QAAC;IACjE;AACF;AAEA,gGAAgG,GAChG,OAAO,eAAeC,uBACpBlD,QAAyB,EACzBwC,KAAsB,EACtBnB,UAA+C,CAAC,CAAC;QAE/BA,oBACJA,gBAKDmB;IANb,MAAMhE,aAAY6C,qBAAAA,QAAQ7C,SAAS,YAAjB6C,qBAAqBjF,cAAcqC,GAAG,GAAGD,SAAS;IACpE,MAAM0B,SAAQmB,iBAAAA,QAAQnB,KAAK,YAAbmB,iBAAiBE,KAAKC,GAAG;IACvC,IAAI,CAAClC,cAAcU,SAASb,OAAO,EAAEqD,MAAMvD,GAAG,CAAC,SAAS,OAAO;IAC/D,MAAMwD,QACJD,MAAMvD,GAAG,CAAC,YAAa,MAAMhC,eAAeuB,WAAWwB,SAAStB,MAAM,EAAEsB,SAASrB,SAAS;IAC5F,IAAI,CAAC8D,OAAO,OAAO;IACnB,MAAMU,QAAOX,aAAAA,MAAMvD,GAAG,CAAC,mBAAVuD,aAAqB;IAClC,MAAMxF,eACJwB,WACAwB,SAAStB,MAAM,EACfsB,SAASrB,SAAS,EAClB8D,OACA;QAAEW,IAAID,KAAKE,IAAI,GAAGN,UAAU,CAAC;QAAMI;IAAK,GACxCjD;IAEF,MAAM,EAAEG,KAAK,EAAEC,MAAM,EAAE,GAAG9D,iBAAiB2G;IAC3C,IAAI9C,UAAU,YAAYA,UAAU,WAAW;QAC7C,MAAMN,oBAAoBC,UAAU;YAAEK;YAAOC;QAAO,GAAGJ;IACzD;IACA,OAAO;AACT;AAEA,yDAAyD,GACzD,OAAO,eAAeoD,eAAevC,OAAgB,EAAEpD,OAAoB;IACzE,MAAMqC,WAAW,MAAM1B,qBAAqBX,SAAS;IACrD,IAAI,CAACqC,UAAU,OAAO9B;IACtB,MAAMsE,QAAQ,IAAIe,IAAIxC,QAAQyC,GAAG,EAAEC,YAAY;IAC/C,MAAMC,SAAS3C,QAAQ2C,MAAM,CAACC,WAAW;IACzC,IAAID,WAAW,QAAQ;QACrB,IAAItC;QACJ,IAAI;YACFA,OAAOwC,KAAKC,KAAK,CAAC,MAAM/C,SAASC;QACnC,EAAE,eAAM;YACN,OAAO7C;QACT;QACA,MAAM4F,SAAS,MAAM3C,eAAenB,UAAUoB,eAAAA,OAAQ,CAAC;QACvD,IAAI,CAAC0C,QAAQ,OAAO5F;QACpB,OAAOC,SAAS4F,IAAI,CAACD,QAAQ;YAAEzF,SAASf;QAAS;IACnD;IACA,0EAA0E;IAC1E,sEAAsE;IACtE,6CAA6C;IAC7C,IAAIoG,WAAW,YAAaA,WAAW,SAASlB,MAAMwB,GAAG,CAAC,WAAY;QACpE,MAAMZ,KAAK,MAAMF,uBAAuBlD,UAAUwC;QAClD,OAAOY,KAAK,IAAIjF,SAAS,MAAM;YAAEC,QAAQ;YAAKC,SAASf;QAAS,KAAKY;IACvE;IACA,IAAIwF,WAAW,OAAO;QACpB,MAAMd,MAAM,MAAML,qBAAqBvC,UAAUwC;QACjD,IAAI,CAACI,KAAK,OAAO1E;QACjB,MAAMkD,OACJ,OAAOwB,IAAIxB,IAAI,KAAK,WAChBwB,IAAIxB,IAAI,GACRwB,IAAIxB,IAAI,CAAC6C,MAAM,CAACtD,KAAK,CAACiC,IAAIxB,IAAI,CAAC8C,UAAU,EAAEtB,IAAIxB,IAAI,CAAC8C,UAAU,GAAGtB,IAAIxB,IAAI,CAAC+C,UAAU;QAC1F,OAAO,IAAIhG,SAASiD,MAAkB;YACpChD,QAAQ;YACRC,SAAS,aAAKf;gBAAU,gBAAgBsF,IAAII,WAAW;;QACzD;IACF;IACA,OAAO,IAAI7E,SAAS,MAAM;QAAEC,QAAQ;QAAKC,SAASf;IAAS;AAC7D;AAEA;;2CAE2C,GAE3C;;;;CAIC,GACD,OAAO,eAAe8G,gBACpBpE,QAAyB,EACzBqE,IAAqB,EACrBhD,UAAiF,CAAC,CAAC;QAEjEA,oBACJA,gBAEKgD;IAHnB,MAAM7F,aAAY6C,qBAAAA,QAAQ7C,SAAS,YAAjB6C,qBAAqBjF,cAAcqC,GAAG,GAAGD,SAAS;IACpE,MAAM0B,SAAQmB,iBAAAA,QAAQnB,KAAK,YAAbmB,iBAAiBE,KAAKC,GAAG;IACvC,IAAI,CAAClC,cAAcU,SAASb,OAAO,EAAEkF,KAAKpF,GAAG,CAAC,QAAQ,OAAO;IAC7D,MAAMqF,cAAaD,YAAAA,KAAKpF,GAAG,CAAC,6BAAToF,YAA8B;IACjD,IAAIC,eAAe,cAAc;YAMlBjD;QALb,+EAA+E;QAC/E,MAAMkD,OAAOvE,SAASb,OAAO,CAACf,MAAM;QACpC,MAAMiC,QACJkE,QAAQA,KAAKlE,KAAK,KAAK,aAAaH,QAAQqE,KAAK7D,IAAI,GAAG,KAAK,KAAK,OAAO6D,KAAKlE,KAAK,GAAG;QACxF,MAAMN,oBAAoBC,UAAU;YAAEK;YAAOC,MAAM,EAAEiE,wBAAAA,KAAMjE,MAAM;QAAC,GAAGJ;QACrE,IAAI,CAAE,MAAM,EAACmB,mBAAAA,QAAQW,OAAO,YAAfX,mBAAoB,IAAM1B,gBAAgBK,SAAStB,MAAM,MAAQ,OAAO;QACrF,MAAMgE,UAAU,MAAM5F,kBAAkB0B,WAAWwB,SAAStB,MAAM,EAAEsB,SAASrB,SAAS,EAAEuB;QACxF,IAAI,CAACwC,SAAS,OAAO;QACrB,OAAOjG,6BAA6BW,iBAAiBsF,QAAQE,GAAG,EAAE5C,SAASb,OAAO,GAAG;YACnFsD,OAAOC,QAAQN,EAAE;YACjBa,SAASjD,SAASb,OAAO,CAAC8D,OAAO;QACnC;IACF;IACA,IAAIqB,eAAe,eAAe;YACOD;QAAvC,MAAMG,UAAU9H,wBAAuB2H,aAAAA,KAAKpF,GAAG,CAAC,2BAAToF,aAA4B;QACnE,KAAK,MAAMzC,UAAU4C,QAAS;YAC5B,MAAMxH,eACJwB,WACAwB,SAAStB,MAAM,EACfsB,SAASrB,SAAS,EAClBiD,OAAOa,KAAK,EACZ;gBAAEW,IAAIxB,OAAO6C,OAAO;gBAAEtB,MAAMvB,OAAOuB,IAAI,IAAKvB,CAAAA,OAAO6C,OAAO,GAAG,YAAY,QAAO;YAAG,GACnFvE;QAEJ;QACA,MAAMqE,OAAOC,OAAO,CAACA,QAAQvD,MAAM,GAAG,EAAE;QACxC,IAAIsD,MAAM;YACR,MAAM,EAAElE,KAAK,EAAEC,MAAM,EAAE,GAAGhE,kBAAkBiI;YAC5C,MAAMxE,oBAAoBC,UAAU;gBAAEK;gBAAOC;YAAO,GAAGJ;QACzD;QACA,OAAO;IACT;IACA,OAAO;AACT;AAEA,yDAAyD,GACzD,OAAO,eAAewE,4BACpB3D,OAAgB,EAChBpD,OAAoB;IAEpB,IAAIoD,QAAQ2C,MAAM,CAACC,WAAW,OAAO,QAAQ;QAC3C,OAAO,IAAIxF,SAAS,MAAM;YAAEC,QAAQ;YAAKC,SAASf;QAAS;IAC7D;IACA,MAAM0C,WAAW,MAAM1B,qBAAqBX,SAAS;IACrD,IAAI,CAACqC,UAAU,OAAO9B;IACtB,MAAM4F,SAAS,MAAMM,gBAAgBpE,UAAU,IAAI2E,gBAAgB,MAAM7D,SAASC;IAClF,IAAI+C,WAAW,MAAM,OAAO5F;IAC5B,OAAO,IAAIC,SAAS2F,QAAQ;QAC1B1F,QAAQ;QACRC,SAAS,aAAKf;YAAU,gBAAgB;;IAC1C;AACF"}
@@ -0,0 +1,39 @@
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 { PrinterBrand } from '../model/commerce-printers';
18
+ /**
19
+ * The per-printer secret in a cloud printer's poll URL (AGL-3619).
20
+ *
21
+ * DERIVED, NOT STORED: `HMAC(TOKEN_SIGNING_SECRET, printer:{hostId}:{printerId}:{version})`,
22
+ * the supplier-token construction (`supplier-update.ts`). Nothing secret sits
23
+ * in a Firestore document a client can read, a manager can be shown the URL
24
+ * again whenever they need to paste it, and "Regenerate URL" invalidates the
25
+ * old one by bumping `secretVersion` on the printer.
26
+ *
27
+ * It rides in the URL PATH rather than in HTTP authentication because the two
28
+ * vendors disagree: Star CloudPRNT offers Basic and Epson Server Direct Print
29
+ * offers Digest, and both accept any https URL. The printer's own identity
30
+ * (Star's MAC, Epson's ID) is checked as well, so the URL alone does not let
31
+ * a different device drain the queue.
32
+ */
33
+ export declare function printerSecret(hostId: string, printerId: string, version: number): string;
34
+ /** Constant-time comparison of a presented secret with the printer's current one. */
35
+ export declare function printerSecretMatches(hostId: string, printerId: string, version: number, presented: unknown): boolean;
36
+ /** The route each brand polls, under the console's plugin API dispatcher. */
37
+ export declare const PRINTER_POLL_ROUTE: Record<PrinterBrand, string>;
38
+ /** The full https URL a manager pastes into the printer's web configuration. */
39
+ export declare function printerPollUrl(brand: PrinterBrand, hostId: string, printerId: string, version: number): string;
@@ -0,0 +1,56 @@
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 { createHmac, timingSafeEqual } from "crypto";
17
+ import { platformConsoleOrigin } from "@aglyn/aglyn/app-utils/platform-brand";
18
+ import { tokenSigningSecret } from "./download.js";
19
+ /**
20
+ * The per-printer secret in a cloud printer's poll URL (AGL-3619).
21
+ *
22
+ * DERIVED, NOT STORED: `HMAC(TOKEN_SIGNING_SECRET, printer:{hostId}:{printerId}:{version})`,
23
+ * the supplier-token construction (`supplier-update.ts`). Nothing secret sits
24
+ * in a Firestore document a client can read, a manager can be shown the URL
25
+ * again whenever they need to paste it, and "Regenerate URL" invalidates the
26
+ * old one by bumping `secretVersion` on the printer.
27
+ *
28
+ * It rides in the URL PATH rather than in HTTP authentication because the two
29
+ * vendors disagree: Star CloudPRNT offers Basic and Epson Server Direct Print
30
+ * offers Digest, and both accept any https URL. The printer's own identity
31
+ * (Star's MAC, Epson's ID) is checked as well, so the URL alone does not let
32
+ * a different device drain the queue.
33
+ */ export function printerSecret(hostId, printerId, version) {
34
+ return createHmac('sha256', tokenSigningSecret()).update(`printer:${hostId}:${printerId}:${Math.max(0, Math.floor(Number(version) || 0))}`).digest('hex').slice(0, 40);
35
+ }
36
+ /** Constant-time comparison of a presented secret with the printer's current one. */ export function printerSecretMatches(hostId, printerId, version, presented) {
37
+ const candidate = typeof presented === 'string' ? presented.trim().toLowerCase() : '';
38
+ if (!/^[0-9a-f]{40}$/.test(candidate)) return false;
39
+ let expected;
40
+ try {
41
+ expected = printerSecret(hostId, printerId, version);
42
+ } catch (unused) {
43
+ // TOKEN_SIGNING_SECRET is not configured: nothing can authenticate.
44
+ return false;
45
+ }
46
+ return timingSafeEqual(Buffer.from(candidate), Buffer.from(expected));
47
+ }
48
+ /** The route each brand polls, under the console's plugin API dispatcher. */ export const PRINTER_POLL_ROUTE = {
49
+ star: 'commerce/cloudprnt',
50
+ epson: 'commerce/epson-sdp'
51
+ };
52
+ /** The full https URL a manager pastes into the printer's web configuration. */ export function printerPollUrl(brand, hostId, printerId, version) {
53
+ return `${platformConsoleOrigin()}/api/${PRINTER_POLL_ROUTE[brand]}/` + `${encodeURIComponent(hostId)}/${encodeURIComponent(printerId)}/` + printerSecret(hostId, printerId, version);
54
+ }
55
+
56
+ //# sourceMappingURL=printer-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/printer-secret.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 { createHmac, timingSafeEqual } from 'crypto'\nimport { platformConsoleOrigin } from '@aglyn/aglyn/app-utils/platform-brand'\nimport type { PrinterBrand } from '../model/commerce-printers'\nimport { tokenSigningSecret } from './download'\n\n/**\n * The per-printer secret in a cloud printer's poll URL (AGL-3619).\n *\n * DERIVED, NOT STORED: `HMAC(TOKEN_SIGNING_SECRET, printer:{hostId}:{printerId}:{version})`,\n * the supplier-token construction (`supplier-update.ts`). Nothing secret sits\n * in a Firestore document a client can read, a manager can be shown the URL\n * again whenever they need to paste it, and \"Regenerate URL\" invalidates the\n * old one by bumping `secretVersion` on the printer.\n *\n * It rides in the URL PATH rather than in HTTP authentication because the two\n * vendors disagree: Star CloudPRNT offers Basic and Epson Server Direct Print\n * offers Digest, and both accept any https URL. The printer's own identity\n * (Star's MAC, Epson's ID) is checked as well, so the URL alone does not let\n * a different device drain the queue.\n */\nexport function printerSecret(hostId: string, printerId: string, version: number): string {\n return createHmac('sha256', tokenSigningSecret())\n .update(`printer:${hostId}:${printerId}:${Math.max(0, Math.floor(Number(version) || 0))}`)\n .digest('hex')\n .slice(0, 40)\n}\n\n/** Constant-time comparison of a presented secret with the printer's current one. */\nexport function printerSecretMatches(\n hostId: string,\n printerId: string,\n version: number,\n presented: unknown,\n): boolean {\n const candidate = typeof presented === 'string' ? presented.trim().toLowerCase() : ''\n if (!/^[0-9a-f]{40}$/.test(candidate)) return false\n let expected: string\n try {\n expected = printerSecret(hostId, printerId, version)\n } catch {\n // TOKEN_SIGNING_SECRET is not configured: nothing can authenticate.\n return false\n }\n return timingSafeEqual(Buffer.from(candidate), Buffer.from(expected))\n}\n\n/** The route each brand polls, under the console's plugin API dispatcher. */\nexport const PRINTER_POLL_ROUTE: Record<PrinterBrand, string> = {\n star: 'commerce/cloudprnt',\n epson: 'commerce/epson-sdp',\n}\n\n/** The full https URL a manager pastes into the printer's web configuration. */\nexport function printerPollUrl(\n brand: PrinterBrand,\n hostId: string,\n printerId: string,\n version: number,\n): string {\n return (\n `${platformConsoleOrigin()}/api/${PRINTER_POLL_ROUTE[brand]}/` +\n `${encodeURIComponent(hostId)}/${encodeURIComponent(printerId)}/` +\n printerSecret(hostId, printerId, version)\n )\n}\n"],"names":["createHmac","timingSafeEqual","platformConsoleOrigin","tokenSigningSecret","printerSecret","hostId","printerId","version","update","Math","max","floor","Number","digest","slice","printerSecretMatches","presented","candidate","trim","toLowerCase","test","expected","Buffer","from","PRINTER_POLL_ROUTE","star","epson","printerPollUrl","brand","encodeURIComponent"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,UAAU,EAAEC,eAAe,QAAQ,SAAQ;AACpD,SAASC,qBAAqB,QAAQ,wCAAuC;AAE7E,SAASC,kBAAkB,QAAQ,gBAAY;AAE/C;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,cAAcC,MAAc,EAAEC,SAAiB,EAAEC,OAAe;IAC9E,OAAOP,WAAW,UAAUG,sBACzBK,MAAM,CAAC,CAAC,QAAQ,EAAEH,OAAO,CAAC,EAAEC,UAAU,CAAC,EAAEG,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAACC,OAAOL,YAAY,KAAK,EACxFM,MAAM,CAAC,OACPC,KAAK,CAAC,GAAG;AACd;AAEA,mFAAmF,GACnF,OAAO,SAASC,qBACdV,MAAc,EACdC,SAAiB,EACjBC,OAAe,EACfS,SAAkB;IAElB,MAAMC,YAAY,OAAOD,cAAc,WAAWA,UAAUE,IAAI,GAAGC,WAAW,KAAK;IACnF,IAAI,CAAC,iBAAiBC,IAAI,CAACH,YAAY,OAAO;IAC9C,IAAII;IACJ,IAAI;QACFA,WAAWjB,cAAcC,QAAQC,WAAWC;IAC9C,EAAE,eAAM;QACN,oEAAoE;QACpE,OAAO;IACT;IACA,OAAON,gBAAgBqB,OAAOC,IAAI,CAACN,YAAYK,OAAOC,IAAI,CAACF;AAC7D;AAEA,2EAA2E,GAC3E,OAAO,MAAMG,qBAAmD;IAC9DC,MAAM;IACNC,OAAO;AACT,EAAC;AAED,8EAA8E,GAC9E,OAAO,SAASC,eACdC,KAAmB,EACnBvB,MAAc,EACdC,SAAiB,EACjBC,OAAe;IAEf,OACE,GAAGL,wBAAwB,KAAK,EAAEsB,kBAAkB,CAACI,MAAM,CAAC,CAAC,CAAC,GAC9D,GAAGC,mBAAmBxB,QAAQ,CAAC,EAAEwB,mBAAmBvB,WAAW,CAAC,CAAC,GACjEF,cAAcC,QAAQC,WAAWC;AAErC"}