@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.287
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.
- package/README.md +1 -1
- package/package.json +13 -13
- package/src/lib/components/cart.js +25 -12
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +70 -13
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +2 -1
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/payment-methods-card.component.js +1 -1
- package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
- package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
- package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
- package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
- package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
- package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
- package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
- package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
- package/src/lib/components/console/pos/use-pos-display.js +50 -0
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
- package/src/lib/components/console/pos-cellular-control.component.js +211 -0
- package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
- package/src/lib/components/console/pos-devices-card.component.js +47 -15
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
- package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-display-page.component.js +44 -2
- package/src/lib/components/console/pos-display-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
- package/src/lib/components/console/pos-hardware-card.component.js +157 -36
- package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
- package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
- package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
- package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
- package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
- package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.d.ts +1 -1
- package/src/lib/components/console/pos-page.component.js +63 -12
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
- package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
- package/src/lib/components/console/product-check-in-fields.component.js +60 -14
- package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +44 -1
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
- package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
- package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
- package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
- package/src/lib/components/console/product-register-fields.component.js +31 -2
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +11 -2
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
- package/src/lib/components/console/register-hardware-card.component.js +56 -27
- package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
- package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
- package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +9 -0
- package/src/lib/components/console/reservations-card.component.js +158 -23
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js +1 -1
- package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
- package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
- package/src/lib/components/console/shipstation-card.component.js +3 -3
- package/src/lib/components/console/shipstation-card.component.js.map +1 -1
- package/src/lib/components/product-detail.d.ts +4 -0
- package/src/lib/components/product-detail.js +40 -5
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/components/product-reviews.js +28 -11
- package/src/lib/components/product-reviews.js.map +1 -1
- package/src/lib/components/reservation-widget.js +28 -5
- package/src/lib/components/reservation-widget.js.map +1 -1
- package/src/lib/components/use-day-picker.d.ts +25 -0
- package/src/lib/components/use-day-picker.js +57 -0
- package/src/lib/components/use-day-picker.js.map +1 -0
- package/src/lib/constants/operator-alerts.d.ts +55 -0
- package/src/lib/constants/operator-alerts.js +156 -1
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/declarations.console-server.js +54 -1
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +4 -2
- package/src/lib/declarations.js +11 -4
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +9 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/model/commerce-cart.d.ts +9 -1
- package/src/lib/model/commerce-cart.js +4 -3
- package/src/lib/model/commerce-cart.js.map +1 -1
- package/src/lib/model/commerce-check-in-product.d.ts +26 -0
- package/src/lib/model/commerce-check-in-product.js +64 -2
- package/src/lib/model/commerce-check-in-product.js.map +1 -1
- package/src/lib/model/commerce-check-in-record.d.ts +127 -0
- package/src/lib/model/commerce-check-in-record.js +36 -0
- package/src/lib/model/commerce-check-in-record.js.map +1 -0
- package/src/lib/model/commerce-check-in.d.ts +91 -87
- package/src/lib/model/commerce-check-in.js +186 -62
- package/src/lib/model/commerce-check-in.js.map +1 -1
- package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
- package/src/lib/model/commerce-kiosk-offer.js +35 -0
- package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +76 -0
- package/src/lib/model/commerce-orders.js +6 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
- package/src/lib/model/commerce-pos-day-report.js +39 -2
- package/src/lib/model/commerce-pos-day-report.js.map +1 -1
- package/src/lib/model/commerce-pos-offline.d.ts +1 -1
- package/src/lib/model/commerce-pos-offline.js +6 -1
- package/src/lib/model/commerce-pos-offline.js.map +1 -1
- package/src/lib/model/commerce-pos-ops.js +3 -2
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +36 -3
- package/src/lib/model/commerce-pos.js +14 -6
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-receipt.js +3 -2
- package/src/lib/model/commerce-receipt.js.map +1 -1
- package/src/lib/model/commerce-reservations.d.ts +69 -4
- package/src/lib/model/commerce-reservations.js +57 -5
- package/src/lib/model/commerce-reservations.js.map +1 -1
- package/src/lib/model/commerce.d.ts +66 -0
- package/src/lib/model/commerce.js +15 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/order-list-fields.d.ts +11 -0
- package/src/lib/model/order-list-fields.js +17 -1
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/own-store-tax-summary.d.ts +152 -0
- package/src/lib/model/own-store-tax-summary.js +288 -0
- package/src/lib/model/own-store-tax-summary.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +67 -0
- package/src/lib/model/plugin-permissions.js +224 -7
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/model/pos-cellular.d.ts +223 -0
- package/src/lib/model/pos-cellular.js +293 -0
- package/src/lib/model/pos-cellular.js.map +1 -0
- package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
- package/src/lib/model/pos-hardware-in-person.js +224 -0
- package/src/lib/model/pos-hardware-in-person.js.map +1 -0
- package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
- package/src/lib/model/pos-hardware-tax-summary.js +225 -0
- package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
- package/src/lib/model/pos-hardware-terms.d.ts +74 -0
- package/src/lib/model/pos-hardware-terms.js +115 -0
- package/src/lib/model/pos-hardware-terms.js.map +1 -0
- package/src/lib/model/pos-hardware.d.ts +349 -7
- package/src/lib/model/pos-hardware.js +291 -20
- package/src/lib/model/pos-hardware.js.map +1 -1
- package/src/lib/model/product-write.d.ts +10 -0
- package/src/lib/model/product-write.js +4 -2
- package/src/lib/model/product-write.js.map +1 -1
- package/src/lib/plugin.js +16 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/billing-webhook.js +25 -1
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cancel-order.js +7 -5
- package/src/lib/server/cancel-order.js.map +1 -1
- package/src/lib/server/cart-checkout.js +20 -8
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.js +29 -0
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/checkout.js +42 -13
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/collection-membership.d.ts +4 -0
- package/src/lib/server/collection-membership.js +5 -10
- package/src/lib/server/collection-membership.js.map +1 -1
- package/src/lib/server/commerce-site-keys.d.ts +29 -0
- package/src/lib/server/commerce-site-keys.js +40 -0
- package/src/lib/server/commerce-site-keys.js.map +1 -0
- package/src/lib/server/draft-order.js +8 -5
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/fulfill-order.js +7 -5
- package/src/lib/server/fulfill-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +8 -5
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.js +9 -6
- package/src/lib/server/local-fulfillment-status.js.map +1 -1
- package/src/lib/server/member-post.js +6 -5
- package/src/lib/server/member-post.js.map +1 -1
- package/src/lib/server/membership-admin-password.d.ts +4 -2
- package/src/lib/server/membership-admin-password.js +10 -8
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-admin-remove.d.ts +7 -5
- package/src/lib/server/membership-admin-remove.js +9 -9
- package/src/lib/server/membership-admin-remove.js.map +1 -1
- package/src/lib/server/order-notifications.js +5 -2
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/order-print.js +7 -5
- package/src/lib/server/order-print.js.map +1 -1
- package/src/lib/server/order-receipt-send.js +8 -5
- package/src/lib/server/order-receipt-send.js.map +1 -1
- package/src/lib/server/orders-shipping-prepare.js +9 -6
- package/src/lib/server/orders-shipping-prepare.js.map +1 -1
- package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
- package/src/lib/server/own-store-tax-return-source.js +312 -0
- package/src/lib/server/own-store-tax-return-source.js.map +1 -0
- package/src/lib/server/payment-methods.js +13 -9
- package/src/lib/server/payment-methods.js.map +1 -1
- package/src/lib/server/pos-auth.d.ts +37 -6
- package/src/lib/server/pos-auth.js +40 -15
- package/src/lib/server/pos-auth.js.map +1 -1
- package/src/lib/server/pos-cellular-billing.d.ts +81 -0
- package/src/lib/server/pos-cellular-billing.js +711 -0
- package/src/lib/server/pos-cellular-billing.js.map +1 -0
- package/src/lib/server/pos-cellular-notify.d.ts +47 -0
- package/src/lib/server/pos-cellular-notify.js +150 -0
- package/src/lib/server/pos-cellular-notify.js.map +1 -0
- package/src/lib/server/pos-cellular.d.ts +88 -0
- package/src/lib/server/pos-cellular.js +339 -0
- package/src/lib/server/pos-cellular.js.map +1 -0
- package/src/lib/server/pos-check-in.d.ts +5 -1
- package/src/lib/server/pos-check-in.js +296 -28
- package/src/lib/server/pos-check-in.js.map +1 -1
- package/src/lib/server/pos-day-report.js +29 -3
- package/src/lib/server/pos-day-report.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +16 -0
- package/src/lib/server/pos-display.js +129 -2
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-hardware-admin.d.ts +10 -1
- package/src/lib/server/pos-hardware-admin.js +250 -84
- package/src/lib/server/pos-hardware-admin.js.map +1 -1
- package/src/lib/server/pos-hardware-attach.d.ts +105 -0
- package/src/lib/server/pos-hardware-attach.js +443 -0
- package/src/lib/server/pos-hardware-attach.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
- package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
- package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
- package/src/lib/server/pos-hardware-buyer-record.js +86 -0
- package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
- package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
- package/src/lib/server/pos-hardware-cancel.js +147 -0
- package/src/lib/server/pos-hardware-cancel.js.map +1 -0
- package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
- package/src/lib/server/pos-hardware-closure-notices.js +85 -0
- package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
- package/src/lib/server/pos-hardware-closure.d.ts +60 -0
- package/src/lib/server/pos-hardware-closure.js +153 -0
- package/src/lib/server/pos-hardware-closure.js.map +1 -0
- package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
- package/src/lib/server/pos-hardware-in-person.js +236 -0
- package/src/lib/server/pos-hardware-in-person.js.map +1 -0
- package/src/lib/server/pos-hardware-notify.d.ts +40 -2
- package/src/lib/server/pos-hardware-notify.js +195 -14
- package/src/lib/server/pos-hardware-notify.js.map +1 -1
- package/src/lib/server/pos-hardware-readers.d.ts +115 -0
- package/src/lib/server/pos-hardware-readers.js +430 -0
- package/src/lib/server/pos-hardware-readers.js.map +1 -0
- package/src/lib/server/pos-hardware-returns.d.ts +116 -0
- package/src/lib/server/pos-hardware-returns.js +502 -0
- package/src/lib/server/pos-hardware-returns.js.map +1 -0
- package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
- package/src/lib/server/pos-hardware-sale-fields.js +44 -0
- package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
- package/src/lib/server/pos-hardware-sale.d.ts +54 -0
- package/src/lib/server/pos-hardware-sale.js +369 -0
- package/src/lib/server/pos-hardware-sale.js.map +1 -0
- package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
- package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
- package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
- package/src/lib/server/pos-hardware-terms.d.ts +64 -0
- package/src/lib/server/pos-hardware-terms.js +154 -0
- package/src/lib/server/pos-hardware-terms.js.map +1 -0
- package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
- package/src/lib/server/pos-hardware-user-eraser.js +31 -7
- package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
- package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
- package/src/lib/server/pos-hardware-webhook.js +51 -6
- package/src/lib/server/pos-hardware-webhook.js.map +1 -1
- package/src/lib/server/pos-hardware.d.ts +74 -1
- package/src/lib/server/pos-hardware.js +175 -10
- package/src/lib/server/pos-hardware.js.map +1 -1
- package/src/lib/server/pos-kiosk.d.ts +2 -0
- package/src/lib/server/pos-kiosk.js +17 -12
- package/src/lib/server/pos-kiosk.js.map +1 -1
- package/src/lib/server/pos-offline-card-order.d.ts +64 -0
- package/src/lib/server/pos-offline-card-order.js +102 -0
- package/src/lib/server/pos-offline-card-order.js.map +1 -0
- package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
- package/src/lib/server/pos-offline-card-reconcile.js +215 -18
- package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
- package/src/lib/server/pos-offline-sync.d.ts +39 -0
- package/src/lib/server/pos-offline-sync.js +190 -55
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-ops-gate.d.ts +15 -4
- package/src/lib/server/pos-ops-gate.js +42 -9
- package/src/lib/server/pos-ops-gate.js.map +1 -1
- package/src/lib/server/pos-ops-routes.js +24 -0
- package/src/lib/server/pos-ops-routes.js.map +1 -1
- package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
- package/src/lib/server/pos-order-refund-ids.js +31 -0
- package/src/lib/server/pos-order-refund-ids.js.map +1 -0
- package/src/lib/server/pos-order.js +52 -49
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.js +1 -1
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-reader-splash-admin.js +30 -32
- package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
- package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
- package/src/lib/server/pos-reader-splash-images-route.js +113 -0
- package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
- package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
- package/src/lib/server/pos-reader-splash-images.js +123 -0
- package/src/lib/server/pos-reader-splash-images.js.map +1 -0
- package/src/lib/server/pos-reader-splash.d.ts +68 -1
- package/src/lib/server/pos-reader-splash.js +182 -11
- package/src/lib/server/pos-reader-splash.js.map +1 -1
- package/src/lib/server/pos-readers.d.ts +29 -0
- package/src/lib/server/pos-readers.js +134 -35
- package/src/lib/server/pos-readers.js.map +1 -1
- package/src/lib/server/pos-return.d.ts +10 -0
- package/src/lib/server/pos-return.js +26 -1
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.js +6 -1
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +11 -0
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/pos-staff-pin.js +25 -20
- package/src/lib/server/pos-staff-pin.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +14 -4
- package/src/lib/server/pos-terminal.js +34 -38
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/printers.d.ts +7 -3
- package/src/lib/server/printers.js +18 -12
- package/src/lib/server/printers.js.map +1 -1
- package/src/lib/server/product-drafts.d.ts +11 -1
- package/src/lib/server/product-drafts.js +12 -8
- package/src/lib/server/product-drafts.js.map +1 -1
- package/src/lib/server/product.d.ts +15 -1
- package/src/lib/server/product.js +16 -3
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/products-write.d.ts +26 -2
- package/src/lib/server/products-write.js +19 -7
- package/src/lib/server/products-write.js.map +1 -1
- package/src/lib/server/refund.js +34 -11
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/reservation-availability-query.d.ts +8 -0
- package/src/lib/server/reservation-availability-query.js +11 -1
- package/src/lib/server/reservation-availability-query.js.map +1 -1
- package/src/lib/server/reservation-availability.d.ts +1 -1
- package/src/lib/server/reservation-availability.js +7 -2
- package/src/lib/server/reservation-availability.js.map +1 -1
- package/src/lib/server/reservation-guests.d.ts +32 -0
- package/src/lib/server/reservation-guests.js +285 -0
- package/src/lib/server/reservation-guests.js.map +1 -0
- package/src/lib/server/reservation-walk-in.d.ts +11 -1
- package/src/lib/server/reservation-walk-in.js +56 -12
- package/src/lib/server/reservation-walk-in.js.map +1 -1
- package/src/lib/server/reserve.js +18 -5
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/returns.js +9 -6
- package/src/lib/server/returns.js.map +1 -1
- package/src/lib/server/reviews.d.ts +22 -2
- package/src/lib/server/reviews.js +88 -20
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/shipping-connectors.js +10 -11
- package/src/lib/server/shipping-connectors.js.map +1 -1
- package/src/lib/server/site-page-resolver.js +20 -3
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server/store-day.d.ts +33 -0
- package/src/lib/server/store-day.js +46 -0
- package/src/lib/server/store-day.js.map +1 -0
- package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
- package/src/lib/server/store-setup-ai-writer.js +5 -6
- package/src/lib/server/store-setup-ai-writer.js.map +1 -1
- package/src/lib/server/storefront-tax.d.ts +13 -0
- package/src/lib/server/storefront-tax.js +8 -1
- package/src/lib/server/storefront-tax.js.map +1 -1
- package/src/lib/server/tax-return-source.d.ts +32 -3
- package/src/lib/server/tax-return-source.js +99 -20
- package/src/lib/server/tax-return-source.js.map +1 -1
- package/src/lib/server.js +100 -2
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/fake-firestore.js +58 -16
- package/src/lib/testing/fake-firestore.js.map +1 -1
- package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
- package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
- package/src/lib/testing/site-register-permissions.d.ts +29 -0
- package/src/lib/testing/site-register-permissions.js +38 -0
- package/src/lib/testing/site-register-permissions.js.map +1 -0
- package/src/lib/transfer/tracking.server.js +8 -5
- package/src/lib/transfer/tracking.server.js.map +1 -1
- package/src/lib/utils/add-to-cart.d.ts +2 -0
- package/src/lib/utils/add-to-cart.js +6 -3
- package/src/lib/utils/add-to-cart.js.map +1 -1
|
@@ -19,7 +19,8 @@ import { parseMediaCdnScope } from "@aglyn/aglyn/app-utils/media-cdn-scope";
|
|
|
19
19
|
import { formatMediaRef, isMediaCdnPath, MEDIA_CDN_ROUTE, mediaRefFromStorageUrl, parseMediaRef, resolveMediaSrc } from "@aglyn/aglyn/app-utils/media-ref";
|
|
20
20
|
import { checkEntitlement, resolveBrandingProfile } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
21
21
|
import { visibleToHost } from "@aglyn/aglyn/app-utils/scope-tokens";
|
|
22
|
-
import { firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
|
|
22
|
+
import { firebaseAdmin, getOrgDoc, getOrgForHost } from "@aglyn/tenant-data-admin";
|
|
23
|
+
import { siteLockdownJobGate } from "@aglyn/tenant-data-admin/server/tenant-write-lockdown";
|
|
23
24
|
import { isPosReaderSplashChoice, POS_READER_SPLASH_DEVICE_TYPES, POS_READER_SPLASH_FAMILIES, POS_READER_SPLASH_SOURCE_MAX_BYTES, POS_READER_SPLASH_SOURCE_TYPES, posReaderSplashArtworkProblem, posReaderSplashEffectiveChoice } from "../model/pos-reader-splash.js";
|
|
24
25
|
import { authorizePosStaff, posRequestBody } from "./pos-auth.js";
|
|
25
26
|
import { PosReaderSplashRenderError, posReaderSplashImageFacts, renderPosReaderSplash } from "./pos-reader-splash-render.js";
|
|
@@ -60,10 +61,18 @@ import { savePosReaderConfiguration } from "./pos-terminal.js";
|
|
|
60
61
|
* - when the POS devices card saves a choice, or opens and finds the key
|
|
61
62
|
* stale (a logo changed since);
|
|
62
63
|
* - when staff change the default, for every store with a Location
|
|
63
|
-
* (`pos-reader-splash-admin.ts`)
|
|
64
|
+
* (`pos-reader-splash-admin.ts`);
|
|
65
|
+
* - when a logo is saved on the organization profile or the brand, for
|
|
66
|
+
* every store of that workspace with a Location, once the save has
|
|
67
|
+
* answered: core's `org.logo.changed` event ({@link onOrgLogoChanged});
|
|
68
|
+
* - on the commerce plugin's `pos-reader-splash-refresh` beat, for every
|
|
69
|
+
* store with a Location whose key went stale with nobody opening the
|
|
70
|
+
* card: the backstop for an event that failed, and the only path for a
|
|
71
|
+
* logo's file replaced in the media library ({@link refreshPosReaderSplashes}).
|
|
64
72
|
*
|
|
65
|
-
* Never on the payment path
|
|
66
|
-
* and a reader with an older screen
|
|
73
|
+
* Never on the payment path, and never IN FRONT of a logo's save: drawing
|
|
74
|
+
* and uploading takes a second or two, and a reader with an older screen
|
|
75
|
+
* still takes the payment.
|
|
67
76
|
*
|
|
68
77
|
* ## Test mode first
|
|
69
78
|
*
|
|
@@ -72,7 +81,7 @@ import { savePosReaderConfiguration } from "./pos-terminal.js";
|
|
|
72
81
|
*=========================================*/ /** Raised when the drawing or the Location changes how keys are built. */ const RENDER_VERSION = 'v1';
|
|
73
82
|
/** `platformSettings/posReaderSplash`: staff's default screen. */ export const POS_READER_SPLASH_SETTINGS_ID = 'posReaderSplash';
|
|
74
83
|
const firestore = ()=>firebaseAdmin.app().firestore();
|
|
75
|
-
function terminalConfigRef(hostId) {
|
|
84
|
+
export function terminalConfigRef(hostId) {
|
|
76
85
|
return firestore().collection('hosts').doc(hostId).collection('terminal').doc('config');
|
|
77
86
|
}
|
|
78
87
|
export function platformSplashRef() {
|
|
@@ -352,6 +361,38 @@ async function loadSharpFactory() {
|
|
|
352
361
|
}
|
|
353
362
|
return String(body.id);
|
|
354
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Draws each reader family's screen from the plan's source and uploads it to
|
|
366
|
+
* Stripe: the image work, which needs `sharp`. Runs in the images function
|
|
367
|
+
* on Vercel (`pos-reader-splash-images-route.ts`), and in any process off it.
|
|
368
|
+
*/ export async function drawAndUploadPosReaderSplash(hostId, source) {
|
|
369
|
+
const screens = await drawScreens(source);
|
|
370
|
+
const fileIds = {};
|
|
371
|
+
for (const family of POS_READER_SPLASH_FAMILIES){
|
|
372
|
+
fileIds[family.id] = await uploadSplashFile(hostId, family, screens[family.id]);
|
|
373
|
+
}
|
|
374
|
+
return fileIds;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Each family's Stripe file for the plan (AGL-4048): drawn here where this
|
|
378
|
+
* process can draw, else by the images function, which draws the plan with
|
|
379
|
+
* the same key. A refusal meant for the store comes back as its own problem.
|
|
380
|
+
*/ async function posReaderSplashFileIds(hostId, key, source) {
|
|
381
|
+
const images = await import("./pos-reader-splash-images.js");
|
|
382
|
+
const origin = images.posReaderSplashImagesOrigin();
|
|
383
|
+
if (!origin) return drawAndUploadPosReaderSplash(hostId, source);
|
|
384
|
+
try {
|
|
385
|
+
const answer = await images.requestPosReaderSplashImages(origin, {
|
|
386
|
+
op: 'draw',
|
|
387
|
+
hostId,
|
|
388
|
+
key
|
|
389
|
+
});
|
|
390
|
+
return answer.fileIds;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
if (error instanceof images.PosReaderSplashImagesRefusal) throw new PosReaderSplashRenderError(error.message);
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
355
396
|
/** The org that owns the site, with its id on it (`planPosReaderSplash` reads it). */ export async function ownerOrgOf(hostId) {
|
|
356
397
|
var _ref, _owner_org_id;
|
|
357
398
|
const owner = await getOrgForHost(hostId).catch(()=>null);
|
|
@@ -395,16 +436,24 @@ async function loadSharpFactory() {
|
|
|
395
436
|
plan,
|
|
396
437
|
problem: plan.problem
|
|
397
438
|
};
|
|
439
|
+
const failedAtMs = typeof config['splashFailedAtMs'] === 'number' ? config['splashFailedAtMs'] : 0;
|
|
440
|
+
if (options.retryFailedAfterMs && !options.force && config['splashFailedKey'] === plan.key && Date.now() - failedAtMs < options.retryFailedAfterMs) {
|
|
441
|
+
const problem = typeof config['splashProblem'] === 'string' ? config['splashProblem'] : plan.problem;
|
|
442
|
+
return {
|
|
443
|
+
outcome: 'skipped',
|
|
444
|
+
plan,
|
|
445
|
+
problem
|
|
446
|
+
};
|
|
447
|
+
}
|
|
398
448
|
try {
|
|
399
449
|
const params = {};
|
|
400
450
|
if (plan.key === 'none' || !plan.source) {
|
|
401
451
|
// An empty value unsets the device's screen on this configuration.
|
|
402
452
|
for (const deviceType of POS_READER_SPLASH_DEVICE_TYPES)params[deviceType] = '';
|
|
403
453
|
} else {
|
|
404
|
-
const
|
|
454
|
+
const fileIds = await posReaderSplashFileIds(hostId, plan.key, plan.source);
|
|
405
455
|
for (const family of POS_READER_SPLASH_FAMILIES){
|
|
406
|
-
const
|
|
407
|
-
for (const deviceType of family.deviceTypes)params[`${deviceType}[splashscreen]`] = fileId;
|
|
456
|
+
for (const deviceType of family.deviceTypes)params[`${deviceType}[splashscreen]`] = fileIds[family.id];
|
|
408
457
|
}
|
|
409
458
|
}
|
|
410
459
|
const saved = await savePosReaderConfiguration(hostId, params, `splash:${digest(plan.key).slice(0, 24)}`);
|
|
@@ -426,7 +475,8 @@ async function loadSharpFactory() {
|
|
|
426
475
|
if (!(error instanceof PosReaderSplashRenderError)) console.error('[pos-reader-splash]', hostId, error);
|
|
427
476
|
await ref.set({
|
|
428
477
|
splashProblem: problem,
|
|
429
|
-
splashFailedAtMs: Date.now()
|
|
478
|
+
splashFailedAtMs: Date.now(),
|
|
479
|
+
splashFailedKey: plan.key
|
|
430
480
|
}, {
|
|
431
481
|
merge: true
|
|
432
482
|
}).catch(()=>undefined);
|
|
@@ -437,6 +487,126 @@ async function loadSharpFactory() {
|
|
|
437
487
|
};
|
|
438
488
|
}
|
|
439
489
|
}
|
|
490
|
+
/** How many stores one pass reaches, and how many it works on at once. */ export const POS_READER_SPLASH_SWEEP_WINDOW = 400;
|
|
491
|
+
const POS_READER_SPLASH_SWEEP_CONCURRENCY = 4;
|
|
492
|
+
/**
|
|
493
|
+
* Brings every store with a Location up to date with
|
|
494
|
+
* {@link applyPosReaderSplash}, the call the POS devices card makes: a store
|
|
495
|
+
* whose screen key has not moved costs reads and no Stripe call, and one
|
|
496
|
+
* that moved gets exactly one round of uploads. At most
|
|
497
|
+
* {@link POS_READER_SPLASH_SWEEP_WINDOW} stores a pass.
|
|
498
|
+
*/ export async function applyPosReaderSplashToStores(options = {}) {
|
|
499
|
+
var _options_platform;
|
|
500
|
+
const counts = {
|
|
501
|
+
applied: 0,
|
|
502
|
+
unchanged: 0,
|
|
503
|
+
failed: 0,
|
|
504
|
+
skipped: 0,
|
|
505
|
+
more: false
|
|
506
|
+
};
|
|
507
|
+
const platform = (_options_platform = options.platform) != null ? _options_platform : await readPlatformSplash();
|
|
508
|
+
const snapshot = await firestore().collectionGroup('terminal').limit(POS_READER_SPLASH_SWEEP_WINDOW + 1).get();
|
|
509
|
+
const docs = snapshot.docs;
|
|
510
|
+
const hostIds = docs.filter((doc)=>doc.id === 'config' && doc.get('stripeLocationId')).map((doc)=>doc.ref.path.split('/')[1]).filter(Boolean);
|
|
511
|
+
await applyPosReaderSplashQueue(hostIds.slice(0, POS_READER_SPLASH_SWEEP_WINDOW), counts, _extends({}, options, {
|
|
512
|
+
platform,
|
|
513
|
+
orgOf: ownerOrgOf
|
|
514
|
+
}));
|
|
515
|
+
return _extends({}, counts, {
|
|
516
|
+
more: docs.length > POS_READER_SPLASH_SWEEP_WINDOW
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
/** Works through `hostIds` a few at a time, counting each store's outcome into `counts`. */ async function applyPosReaderSplashQueue(hostIds, counts, options) {
|
|
520
|
+
const queue = [
|
|
521
|
+
...hostIds
|
|
522
|
+
];
|
|
523
|
+
await Promise.all(Array.from({
|
|
524
|
+
length: POS_READER_SPLASH_SWEEP_CONCURRENCY
|
|
525
|
+
}, async ()=>{
|
|
526
|
+
for(let hostId = queue.shift(); hostId; hostId = queue.shift()){
|
|
527
|
+
if (options.isLocked && await options.isLocked(hostId)) {
|
|
528
|
+
counts.skipped += 1;
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const result = await applyPosReaderSplash(hostId, _extends({
|
|
532
|
+
org: await options.orgOf(hostId),
|
|
533
|
+
platform: options.platform
|
|
534
|
+
}, options.retryFailedAfterMs ? {
|
|
535
|
+
retryFailedAfterMs: options.retryFailedAfterMs
|
|
536
|
+
} : {}));
|
|
537
|
+
if (result.outcome === 'applied' || result.outcome === 'cleared') counts.applied += 1;
|
|
538
|
+
else if (result.outcome === 'failed') counts.failed += 1;
|
|
539
|
+
else if (result.outcome === 'skipped') counts.skipped += 1;
|
|
540
|
+
else counts.unchanged += 1;
|
|
541
|
+
}
|
|
542
|
+
}));
|
|
543
|
+
}
|
|
544
|
+
/** How long a background pass leaves a screen Stripe refused before trying it again. */ export const POS_READER_SPLASH_RETRY_FAILED_AFTER_MS = 6 * 60 * 60 * 1000;
|
|
545
|
+
/**
|
|
546
|
+
* The `pos-reader-splash-refresh` beat (AGL-4048): a logo changed on the
|
|
547
|
+
* organization profile or the white-label brand, or the logo's file replaced
|
|
548
|
+
* in the media library, reaches the store's readers without anybody opening
|
|
549
|
+
* the POS devices card. The screen's key already moves with each of those,
|
|
550
|
+
* so the beat only has to ask; nothing waits on it, and a save never waits
|
|
551
|
+
* on Stripe. Asks the runner's lockdown gate for every store.
|
|
552
|
+
*/ export async function refreshPosReaderSplashes(gate) {
|
|
553
|
+
const idle = {
|
|
554
|
+
applied: 0,
|
|
555
|
+
unchanged: 0,
|
|
556
|
+
failed: 0,
|
|
557
|
+
skipped: 0,
|
|
558
|
+
more: false
|
|
559
|
+
};
|
|
560
|
+
if (!posTerminalAvailable()) return idle;
|
|
561
|
+
return applyPosReaderSplashToStores({
|
|
562
|
+
isLocked: (hostId)=>gate.isLocked(hostId),
|
|
563
|
+
retryFailedAfterMs: POS_READER_SPLASH_RETRY_FAILED_AFTER_MS
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Core's `org.logo.changed` (AGL-4048): a logo saved on the organization
|
|
568
|
+
* profile or the white-label brand reaches the readers of every store of
|
|
569
|
+
* that workspace now, not on the next beat. Raised after the save has
|
|
570
|
+
* answered, so nobody waits on it.
|
|
571
|
+
*
|
|
572
|
+
* {@link applyPosReaderSplash} for each store, the call the POS devices card
|
|
573
|
+
* makes: a store with no Location, or whose screen does not show the logo
|
|
574
|
+
* that moved (a dark-mode logo, a store showing its own image), costs reads
|
|
575
|
+
* and no Stripe call. A store that is locked is left alone, and a screen
|
|
576
|
+
* Stripe refused waits as it does on the beat; the beat, which stays, is
|
|
577
|
+
* the backstop for anything this misses. Never throws.
|
|
578
|
+
*/ export async function onOrgLogoChanged(payload, gate = siteLockdownJobGate()) {
|
|
579
|
+
var _payload_orgId;
|
|
580
|
+
const counts = {
|
|
581
|
+
applied: 0,
|
|
582
|
+
unchanged: 0,
|
|
583
|
+
failed: 0,
|
|
584
|
+
skipped: 0,
|
|
585
|
+
more: false
|
|
586
|
+
};
|
|
587
|
+
const orgId = String((_payload_orgId = payload.orgId) != null ? _payload_orgId : '').trim();
|
|
588
|
+
if (!orgId || !posTerminalAvailable()) return counts;
|
|
589
|
+
try {
|
|
590
|
+
const org = await getOrgDoc(orgId);
|
|
591
|
+
if (!org) return counts;
|
|
592
|
+
const snapshot = await firestore().collection('hosts').where('orgId', '==', orgId).limit(POS_READER_SPLASH_SWEEP_WINDOW + 1).get();
|
|
593
|
+
const hostIds = snapshot.docs.map((doc)=>String(doc.id));
|
|
594
|
+
await applyPosReaderSplashQueue(hostIds.slice(0, POS_READER_SPLASH_SWEEP_WINDOW), counts, {
|
|
595
|
+
platform: await readPlatformSplash(),
|
|
596
|
+
orgOf: async ()=>_extends({}, org, {
|
|
597
|
+
id: orgId
|
|
598
|
+
}),
|
|
599
|
+
isLocked: (hostId)=>gate.isLocked(hostId),
|
|
600
|
+
retryFailedAfterMs: POS_READER_SPLASH_RETRY_FAILED_AFTER_MS
|
|
601
|
+
});
|
|
602
|
+
return _extends({}, counts, {
|
|
603
|
+
more: hostIds.length > POS_READER_SPLASH_SWEEP_WINDOW
|
|
604
|
+
});
|
|
605
|
+
} catch (error) {
|
|
606
|
+
console.error('[pos-reader-splash] a changed logo could not reach the readers', orgId, error);
|
|
607
|
+
return counts;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
440
610
|
/*==========================================
|
|
441
611
|
* `POST /api/commerce/pos-reader-splash`: the POS devices card's setting.
|
|
442
612
|
*
|
|
@@ -482,7 +652,9 @@ export const posReaderSplashHandler = async (req, res)=>{
|
|
|
482
652
|
});
|
|
483
653
|
const body = posRequestBody(req);
|
|
484
654
|
const hostId = String((_body_hostId = body['hostId']) != null ? _body_hostId : '');
|
|
485
|
-
const
|
|
655
|
+
const action = String((_body_action = body['action']) != null ? _body_action : '');
|
|
656
|
+
// Changing what the readers show is setting them up (AGL-4047); reading it is not.
|
|
657
|
+
const gate = await authorizePosStaff(req, hostId, action === 'save' ? 'posDevices' : undefined);
|
|
486
658
|
if ('error' in gate) return res.status(gate.status).json({
|
|
487
659
|
error: gate.error
|
|
488
660
|
});
|
|
@@ -490,7 +662,6 @@ export const posReaderSplashHandler = async (req, res)=>{
|
|
|
490
662
|
const org = staff.org ? _extends({}, staff.org, {
|
|
491
663
|
id: staff.orgId
|
|
492
664
|
}) : null;
|
|
493
|
-
const action = String((_body_action = body['action']) != null ? _body_action : '');
|
|
494
665
|
try {
|
|
495
666
|
if (action === 'status') return res.status(200).json(await currentStatus(hostId, org));
|
|
496
667
|
if (action !== 'save') return res.status(400).json({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-reader-splash.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 { createHash } from 'node:crypto'\nimport { parseMediaCdnScope, type MediaCdnScope } from '@aglyn/aglyn/app-utils/media-cdn-scope'\nimport {\n formatMediaRef,\n isMediaCdnPath,\n MEDIA_CDN_ROUTE,\n mediaRefFromStorageUrl,\n parseMediaRef,\n resolveMediaSrc,\n} from '@aglyn/aglyn/app-utils/media-ref'\nimport { checkEntitlement, resolveBrandingProfile } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport {\n isPosReaderSplashChoice,\n POS_READER_SPLASH_DEVICE_TYPES,\n POS_READER_SPLASH_FAMILIES,\n POS_READER_SPLASH_SOURCE_MAX_BYTES,\n POS_READER_SPLASH_SOURCE_TYPES,\n posReaderSplashArtworkProblem,\n posReaderSplashEffectiveChoice,\n type PosReaderSplashChoice,\n type PosReaderSplashFamily,\n type PosReaderSplashFamilyId,\n type PosReaderSplashSetting,\n type PosReaderSplashStatus,\n} from '../model/pos-reader-splash'\nimport { authorizePosStaff, posRequestBody } from './pos-auth'\nimport {\n PosReaderSplashRenderError,\n posReaderSplashImageFacts,\n renderPosReaderSplash,\n type RenderedPosReaderSplash,\n} from './pos-reader-splash-render'\nimport { POS_STRIPE_VERSION, posTerminalAvailable } from './pos-stripe'\nimport { savePosReaderConfiguration } from './pos-terminal'\n\n/*==========================================\n * A STORE'S CARD READERS SHOW ITS START-UP SCREEN (AGL-4048).\n *\n * ## Where it lives\n *\n * Readers and Locations are the PLATFORM's (the destination-charge model,\n * `pos-terminal.ts`), one Location per site. The screen is set on that\n * site's one Terminal Configuration, the one reader tipping already uses,\n * per device type (`stripe_s700`, `stripe_s710`, `bbpos_wisepos_e`), from a\n * File uploaded to Stripe with purpose `terminal_reader_splashscreen`.\n *\n * The platform's account-default configuration is NEVER given a screen. A\n * Location without an override inherits it, so an account default would put\n * the platform's brand on a white-label store's readers, which is the one\n * thing the white-label rule forbids. Staff's default screen is applied per\n * Location instead, to the stores that use it.\n *\n * ## What is applied\n *\n * `hosts/{hostId}/terminal/config.splash` holds the store's choice\n * (`model/pos-reader-splash.ts`); the screen applied is described by a KEY\n * built from cheap metadata only: the choice, the platform default's\n * version, the logo's address and its asset's content digest, the picked\n * image's. `splashAppliedKey` records the last key that reached Stripe, so\n * applying again with nothing changed makes no Stripe call at all, and a\n * changed logo, a new staff default or a new choice makes exactly one round\n * of uploads. Every upload and the first configuration write are keyed by\n * content, so a retried apply never makes a second file or configuration.\n *\n * ## When it is applied\n *\n * - when the store's Location is created (its first reader);\n * - when the POS devices card saves a choice, or opens and finds the key\n * stale (a logo changed since);\n * - when staff change the default, for every store with a Location\n * (`pos-reader-splash-admin.ts`).\n *\n * Never on the payment path: drawing and uploading takes a second or two,\n * and a reader with an older screen still takes the payment.\n *\n * ## Test mode first\n *\n * Gated by `posTerminalAvailable()`: always in test mode, in live mode only\n * once `STRIPE_TERMINAL_LIVE_ENABLED` is on, like every reader control.\n *=========================================*/\n\n/** Raised when the drawing or the Location changes how keys are built. */\nconst RENDER_VERSION = 'v1'\n\n/** `platformSettings/posReaderSplash`: staff's default screen. */\nexport const POS_READER_SPLASH_SETTINGS_ID = 'posReaderSplash'\n\n/** One family's default screen, as staff uploaded it. */\nexport interface PlatformSplashImage {\n storagePath: string\n sha256: string\n contentType: 'image/png' | 'image/jpeg'\n bytes: number\n uploadedAtMs: number\n uploadedBy?: string\n}\n\nexport interface PlatformSplashDoc {\n families?: Partial<Record<PosReaderSplashFamilyId, PlatformSplashImage>>\n updatedAtMs?: number\n}\n\nconst firestore = () => firebaseAdmin.app().firestore()\n\nfunction terminalConfigRef(hostId: string) {\n return firestore().collection('hosts').doc(hostId).collection('terminal').doc('config')\n}\n\nexport function platformSplashRef() {\n return firestore().collection('platformSettings').doc(POS_READER_SPLASH_SETTINGS_ID)\n}\n\nexport function posReaderSplashBucket() {\n return firebaseAdmin\n .app()\n .storage()\n .bucket(process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || undefined)\n}\n\nexport async function readPlatformSplash(): Promise<PlatformSplashDoc> {\n const snapshot = await platformSplashRef().get()\n return (snapshot.exists ? snapshot.data() : {}) as PlatformSplashDoc\n}\n\n/** The default is usable once the S700/S710 screen is uploaded; the smaller one is drawn from it if absent. */\nexport function platformSplashReady(doc: PlatformSplashDoc): boolean {\n return Boolean(doc.families?.['portrait-large']?.storagePath)\n}\n\nfunction platformSplashVersion(doc: PlatformSplashDoc): string {\n return POS_READER_SPLASH_FAMILIES.map((family) => doc.families?.[family.id]?.sha256 ?? '-').join('.')\n}\n\nconst digest = (value: string | Buffer) => createHash('sha256').update(value).digest('hex')\n\nconst cleanString = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/*==========================================\n * READING A SOURCE IMAGE.\n *\n * A media value is read from STORAGE, never fetched, when it names this\n * site's library or its org's: the document must be live, not private,\n * visible to this site, its scope not locked and the asset not quarantined,\n * and the object path inside the scope's media prefix (the rules the media\n * CDN serves by). An https address outside the libraries is fetched only from\n * a public address, pinned against DNS rebinding, with no redirects, a\n * timeout and a size cap.\n *=========================================*/\n\ninterface LocatedAsset {\n kind: 'asset'\n scope: MediaCdnScope\n scopeSegment: string\n mediaId: string\n doc: Record<string, unknown>\n /** What changes when the asset's bytes do. */\n version: string\n}\n\ninterface LocatedUrl {\n kind: 'url'\n url: string\n version: string\n}\n\ntype LocatedSource = LocatedAsset | LocatedUrl\n\nasync function locateMediaAsset(\n scopeSegment: string,\n mediaId: string,\n hostId: string,\n orgId: string,\n): Promise<LocatedAsset | null> {\n const scope = parseMediaCdnScope(scopeSegment)\n if (!scope || !/^[A-Za-z0-9_-]{1,64}$/.test(mediaId)) return null\n const owned = scope.isOrg ? scope.scopeId === orgId : scope.scopeId === hostId\n if (!owned) return null\n const snapshot = await firestore()\n .collection(scope.isOrg ? 'orgs' : 'hosts')\n .doc(scope.scopeId)\n .collection('media')\n .doc(mediaId)\n .get()\n const doc = (snapshot.exists ? snapshot.data() : null) as Record<string, unknown> | null\n if (!doc || doc['deletedAt'] || doc['private']) return null\n if (scope.isOrg && !visibleToHost(doc['visibleTo'] as string[] | undefined, hostId)) return null\n if (!/^image\\//.test(String(doc['contentType'] ?? ''))) return null\n if (typeof doc['sizeBytes'] === 'number' && doc['sizeBytes'] > POS_READER_SPLASH_SOURCE_MAX_BYTES) return null\n const version =\n cleanString(doc['contentSha256']) ||\n cleanString(doc['contentHash']) ||\n String(doc['updatedAtMs'] ?? doc['sizeBytes'] ?? '')\n return { kind: 'asset', scope, scopeSegment, mediaId, doc, version }\n}\n\n/** Where a stored logo or image value lives, or null when it cannot be read. */\nasync function locateSource(value: string, hostId: string, orgId: string): Promise<LocatedSource | null> {\n const stored = parseMediaRef(value) ? value : mediaRefFromStorageUrl(value)\n const ref = stored ? parseMediaRef(stored) : null\n if (ref) return locateMediaAsset(ref.scope, ref.mediaId, hostId, orgId)\n if (isMediaCdnPath(value)) {\n const rest = value.slice(`${MEDIA_CDN_ROUTE}/`.length).split('?')[0]\n const slash = rest.indexOf('/')\n if (slash <= 0) return null\n return locateMediaAsset(rest.slice(0, slash), rest.slice(slash + 1), hostId, orgId)\n }\n // `isMediaCdnPath` narrows a string it refuses to `never`; the value is still the string.\n const address: string = value as string\n if (/^https:\\/\\//.test(address) && address.length <= 2000) return { kind: 'url', url: address, version: address }\n return null\n}\n\nasync function readAssetBytes(asset: LocatedAsset): Promise<Buffer | null> {\n const { mediaCdnServeBlock, mediaStoragePathInScope } = await import('./pos-reader-splash-server')\n const blocked = await mediaCdnServeBlock(asset.scope, {\n contentSha256: typeof asset.doc['contentSha256'] === 'string' ? (asset.doc['contentSha256'] as string) : undefined,\n contentHash: typeof asset.doc['contentHash'] === 'string' ? (asset.doc['contentHash'] as string) : undefined,\n scopeSegment: asset.scopeSegment,\n mediaId: asset.mediaId,\n })\n if (blocked) return null\n const objectPath = mediaStoragePathInScope({\n storagePath: asset.doc['storagePath'],\n base: `${asset.scope.isOrg ? 'orgs' : 'hosts'}/${asset.scope.scopeId}`,\n mediaId: asset.mediaId,\n })\n const [buffer] = (await posReaderSplashBucket().file(objectPath).download()) as [Buffer]\n return buffer.length > POS_READER_SPLASH_SOURCE_MAX_BYTES ? null : buffer\n}\n\nconst FETCH_TIMEOUT_MS = 8000\n\nasync function fetchPublicImage(url: string): Promise<Buffer | null> {\n const { createPinnedDispatcher, resolvePublicIp } = await import('./pos-reader-splash-server')\n const pinnedIp = await resolvePublicIp(new URL(url).hostname)\n if (!pinnedIp) return null\n const dispatcher = createPinnedDispatcher(pinnedIp)\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n const init = { redirect: 'error' as const, signal: controller.signal, dispatcher }\n const response = await fetch(url, init as RequestInit)\n if (!response.ok) return null\n if (!/^image\\//.test(response.headers.get('content-type') ?? '')) return null\n const declared = Number(response.headers.get('content-length') ?? 0)\n if (declared > POS_READER_SPLASH_SOURCE_MAX_BYTES) return null\n const buffer = Buffer.from(await response.arrayBuffer())\n return buffer.length > POS_READER_SPLASH_SOURCE_MAX_BYTES ? null : buffer\n } catch {\n return null\n } finally {\n clearTimeout(timeout)\n ;(dispatcher as { close?: () => Promise<void> }).close?.().catch(() => undefined)\n }\n}\n\nasync function readSourceBytes(source: LocatedSource): Promise<Buffer | null> {\n return source.kind === 'asset' ? readAssetBytes(source) : fetchPublicImage(source.url)\n}\n\n/*==========================================\n * WHAT A STORE SHOWS.\n *=========================================*/\n\n/**\n * The workspace's own logo: a white-label workspace's brand logo first,\n * then the logo on its organization profile. Never the platform's: the\n * resolved brand profile falls back to the platform's own logo for a\n * workspace without a brand, so its `logoUrl` is not read here.\n */\nexport function workspaceLogoValue(org: Record<string, any> | null, whiteLabel: boolean): string | null {\n const brand = whiteLabel ? cleanString(org?.['brandingProfile']?.['logoUrl']) : ''\n return brand || cleanString(org?.['logoUrl']) || null\n}\n\ntype SplashSource =\n | { mode: 'platform'; doc: PlatformSplashDoc }\n | { mode: 'logo' | 'artwork'; located: LocatedSource }\n\nexport interface PosReaderSplashPlan {\n choice: PosReaderSplashChoice | null\n effectiveChoice: PosReaderSplashChoice\n whiteLabel: boolean\n productName: string\n platformReady: boolean\n logoValue: string | null\n image: { mediaScope: string; mediaId: string } | null\n /** `none` when the readers show Stripe's standard screen. */\n key: string\n problem: string | null\n source: SplashSource | null\n}\n\nconst NO_LOGO = 'Add a logo to your organization profile to show it on your card readers.'\nconst NO_IMAGE = 'The image picked for your card readers is no longer in your media library. Choose another.'\n\nexport async function planPosReaderSplash(\n hostId: string,\n org: Record<string, any> | null,\n config: Record<string, any> | undefined,\n platform?: PlatformSplashDoc,\n): Promise<PosReaderSplashPlan> {\n const orgId = String(org?.['id'] ?? '')\n const whiteLabel = checkEntitlement(org as any, 'whiteLabel')\n const productName = resolveBrandingProfile(org as any).productName\n const setting = (config?.['splash'] ?? null) as PosReaderSplashSetting | null\n const choice = isPosReaderSplashChoice(setting?.choice) ? setting.choice : null\n const effectiveChoice = posReaderSplashEffectiveChoice(choice, whiteLabel)\n const doc = platform ?? (await readPlatformSplash())\n const logoValue = workspaceLogoValue(org, whiteLabel)\n const image =\n setting?.mediaScope && setting?.mediaId ? { mediaScope: setting.mediaScope, mediaId: setting.mediaId } : null\n const base = {\n choice,\n effectiveChoice,\n whiteLabel,\n productName,\n platformReady: platformSplashReady(doc),\n logoValue,\n image,\n }\n if (effectiveChoice === 'platform') {\n // The white-label rule is in `posReaderSplashEffectiveChoice`; this is\n // the guard behind it, because this branch is the platform's brand.\n if (whiteLabel || !platformSplashReady(doc)) return { ...base, key: 'none', problem: null, source: null }\n return {\n ...base,\n key: `platform:${RENDER_VERSION}:${platformSplashVersion(doc)}`,\n problem: null,\n source: { mode: 'platform', doc },\n }\n }\n if (effectiveChoice === 'logo') {\n const located = logoValue ? await locateSource(logoValue, hostId, orgId) : null\n if (!located) return { ...base, key: 'none', problem: NO_LOGO, source: null }\n return {\n ...base,\n key: `logo:${RENDER_VERSION}:${digest(`${logoValue}|${located.version}`).slice(0, 24)}`,\n problem: null,\n source: { mode: 'logo', located },\n }\n }\n const located = image ? await locateMediaAsset(image.mediaScope, image.mediaId, hostId, orgId) : null\n if (!located) return { ...base, key: 'none', problem: NO_IMAGE, source: null }\n return {\n ...base,\n key: `image:${RENDER_VERSION}:${digest(`${image?.mediaScope}/${image?.mediaId}|${located.version}`).slice(0, 24)}`,\n problem: null,\n source: { mode: 'artwork', located },\n }\n}\n\nasync function loadSharpFactory(): Promise<any> {\n const { loadSharp } = await import('./pos-reader-splash-server')\n return loadSharp()\n}\n\n/** Each family's screen for the plan, ready for Stripe. */\nasync function drawScreens(\n source: SplashSource,\n): Promise<Record<PosReaderSplashFamilyId, RenderedPosReaderSplash>> {\n const sharp = await loadSharpFactory()\n const screens = {} as Record<PosReaderSplashFamilyId, RenderedPosReaderSplash>\n if (source.mode === 'platform') {\n const bucket = posReaderSplashBucket()\n const read = async (image: PlatformSplashImage) =>\n ((await bucket.file(image.storagePath).download()) as [Buffer])[0]\n const large = source.doc.families?.['portrait-large'] as PlatformSplashImage\n const largeBody = await read(large)\n for (const family of POS_READER_SPLASH_FAMILIES) {\n const own = source.doc.families?.[family.id]\n // Staff's own screen for the family is sent as uploaded: it was checked\n // against Stripe's rules for exactly this family then. A family staff\n // left empty is drawn from the S700/S710 screen, the same 9:16.\n screens[family.id] = own?.storagePath\n ? { body: own === large ? largeBody : await read(own), contentType: own.contentType }\n : await renderPosReaderSplash({ source: largeBody, family, mode: 'artwork', sharp })\n }\n return screens\n }\n const bytes = await readSourceBytes(source.located)\n if (!bytes) throw new PosReaderSplashRenderError('That image could not be read.')\n if (source.mode === 'artwork') {\n const facts = await posReaderSplashImageFacts(sharp, bytes)\n const problem = posReaderSplashArtworkProblem({\n contentType: facts?.contentType || null,\n bytes: bytes.length,\n width: facts?.width ?? 0,\n height: facts?.height ?? 0,\n })\n if (problem) throw new PosReaderSplashRenderError(problem)\n }\n for (const family of POS_READER_SPLASH_FAMILIES) {\n screens[family.id] = await renderPosReaderSplash({ source: bytes, family, mode: source.mode, sharp })\n }\n return screens\n}\n\n/** One screen uploaded to Stripe, keyed by its content so a retry makes no second file. */\nasync function uploadSplashFile(\n hostId: string,\n family: PosReaderSplashFamily,\n screen: RenderedPosReaderSplash,\n): Promise<string> {\n const form = new FormData()\n form.append('purpose', 'terminal_reader_splashscreen')\n const extension = screen.contentType === 'image/png' ? 'png' : 'jpg'\n form.append('file', new Blob([new Uint8Array(screen.body)], { type: screen.contentType }), `start-up-${family.id}.${extension}`)\n const response = await fetch('https://files.stripe.com/v1/files', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,\n 'Stripe-Version': POS_STRIPE_VERSION,\n 'Idempotency-Key': `pos-splash-file:${hostId}:${family.id}:${digest(screen.body).slice(0, 32)}`,\n },\n body: form,\n })\n const body = (await response.json().catch(() => ({}))) as { id?: string; error?: { message?: string } }\n if (!response.ok || !body.id) {\n throw new PosReaderSplashRenderError(body.error?.message || 'Stripe did not accept the start-up screen.')\n }\n return String(body.id)\n}\n\n/** The org that owns the site, with its id on it (`planPosReaderSplash` reads it). */\nexport async function ownerOrgOf(hostId: string): Promise<Record<string, any> | null> {\n const owner = await getOrgForHost(hostId).catch(() => null)\n if (!owner?.org) return null\n return { ...(owner.org as Record<string, any>), id: String((owner.org as any).id ?? owner.orgId ?? '') }\n}\n\nexport interface PosReaderSplashApplyResult {\n outcome: 'unchanged' | 'applied' | 'cleared' | 'skipped' | 'failed'\n plan: PosReaderSplashPlan | null\n problem: string | null\n}\n\n/**\n * Puts the store's start-up screen on its readers' configuration when it\n * changed since it was last applied. Never throws: a failure is recorded on\n * the store's terminal document and returned, and the readers keep their\n * previous screen.\n */\nexport async function applyPosReaderSplash(\n hostId: string,\n options: { org?: Record<string, any> | null; platform?: PlatformSplashDoc; force?: boolean } = {},\n): Promise<PosReaderSplashApplyResult> {\n if (!posTerminalAvailable()) return { outcome: 'skipped', plan: null, problem: null }\n const ref = terminalConfigRef(hostId)\n const config = (await ref.get()).data() as Record<string, any> | undefined\n if (!config?.['stripeLocationId']) return { outcome: 'skipped', plan: null, problem: null }\n const org = options.org !== undefined ? options.org : await ownerOrgOf(hostId)\n const plan = await planPosReaderSplash(hostId, org, config, options.platform)\n const applied = typeof config['splashAppliedKey'] === 'string' ? (config['splashAppliedKey'] as string) : null\n // Nothing to show and nothing ever shown: the readers already show\n // Stripe's standard screen, and no Stripe call is needed to keep it.\n if (plan.key === 'none' && (applied === null || applied === 'none') && !options.force) {\n return { outcome: 'unchanged', plan, problem: plan.problem }\n }\n if (plan.key === applied && !options.force) return { outcome: 'unchanged', plan, problem: plan.problem }\n try {\n const params: Record<string, string> = {}\n if (plan.key === 'none' || !plan.source) {\n // An empty value unsets the device's screen on this configuration.\n for (const deviceType of POS_READER_SPLASH_DEVICE_TYPES) params[deviceType] = ''\n } else {\n const screens = await drawScreens(plan.source)\n for (const family of POS_READER_SPLASH_FAMILIES) {\n const fileId = await uploadSplashFile(hostId, family, screens[family.id])\n for (const deviceType of family.deviceTypes) params[`${deviceType}[splashscreen]`] = fileId\n }\n }\n const saved = await savePosReaderConfiguration(hostId, params, `splash:${digest(plan.key).slice(0, 24)}`)\n if (!saved.ok) throw new PosReaderSplashRenderError('Stripe did not accept the start-up screen. Try again.')\n await ref.set(\n {\n splashAppliedKey: plan.key,\n splashAppliedAtMs: Date.now(),\n splashProblem: firebaseAdmin.firestore.FieldValue.delete(),\n },\n { merge: true },\n )\n return { outcome: plan.key === 'none' ? 'cleared' : 'applied', plan, problem: plan.problem }\n } catch (error) {\n const problem =\n error instanceof PosReaderSplashRenderError ? error.message : 'The start-up screen could not be applied. Try again.'\n if (!(error instanceof PosReaderSplashRenderError)) console.error('[pos-reader-splash]', hostId, error)\n await ref.set({ splashProblem: problem, splashFailedAtMs: Date.now() }, { merge: true }).catch(() => undefined)\n return { outcome: 'failed', plan, problem }\n }\n}\n\n/*==========================================\n * `POST /api/commerce/pos-reader-splash`: the POS devices card's setting.\n *\n * status the store's choice and what it shows (re-applies a stale one)\n * save { choice, mediaScope?, mediaId? } — store and apply\n *\n * Gated like a sale (`authorizePosStaff`), as every reader control is.\n *=========================================*/\n\nfunction statusOf(\n plan: PosReaderSplashPlan | null,\n config: Record<string, any> | undefined,\n hostId: string,\n problem: string | null,\n): PosReaderSplashStatus {\n return {\n available: posTerminalAvailable(),\n choice: plan?.choice ?? null,\n effectiveChoice: plan?.effectiveChoice ?? 'platform',\n whiteLabel: plan?.whiteLabel ?? false,\n productName: plan?.productName ?? '',\n platformReady: plan?.platformReady ?? false,\n logoUrl: plan?.logoValue ? resolveMediaSrc(plan.logoValue, { hostId }) ?? null : null,\n image: plan?.image\n ? { ...plan.image, url: resolveMediaSrc(formatMediaRef(plan.image.mediaScope, plan.image.mediaId), { hostId }) ?? null }\n : null,\n locationReady: Boolean(config?.['stripeLocationId']),\n appliedAtMs: typeof config?.['splashAppliedAtMs'] === 'number' ? config['splashAppliedAtMs'] : null,\n problem: problem ?? (typeof config?.['splashProblem'] === 'string' ? config['splashProblem'] : null),\n }\n}\n\nasync function currentStatus(hostId: string, org: Record<string, any> | null): Promise<PosReaderSplashStatus> {\n const result = await applyPosReaderSplash(hostId, { org })\n const config = (await terminalConfigRef(hostId).get()).data() as Record<string, any> | undefined\n const plan = result.plan ?? (await planPosReaderSplash(hostId, org, config))\n return statusOf(plan, config, hostId, result.outcome === 'failed' ? result.problem : plan.problem)\n}\n\nexport const posReaderSplashHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const body = posRequestBody(req)\n const hostId = String(body['hostId'] ?? '')\n const gate = await authorizePosStaff(req, hostId)\n if ('error' in gate) return res.status(gate.status).json({ error: gate.error })\n const staff = gate.staff\n const org = staff.org ? { ...staff.org, id: staff.orgId } : null\n const action = String(body['action'] ?? '')\n try {\n if (action === 'status') return res.status(200).json(await currentStatus(hostId, org))\n if (action !== 'save') return res.status(400).json({ error: 'Unknown action' })\n if (!posTerminalAvailable()) return res.status(409).json({ error: 'Card readers are not available yet.' })\n const choice = body['choice']\n if (!isPosReaderSplashChoice(choice)) return res.status(400).json({ error: 'Choose what your readers show.' })\n const whiteLabel = checkEntitlement(staff.org as any, 'whiteLabel')\n if (choice === 'platform' && whiteLabel) {\n return res.status(400).json({ error: 'Choose your logo or your own image.' })\n }\n const setting: PosReaderSplashSetting = { choice, updatedAtMs: Date.now(), updatedBy: staff.uid }\n if (choice === 'image') {\n const mediaScope = String(body['mediaScope'] ?? '')\n const mediaId = String(body['mediaId'] ?? '')\n const located = await locateMediaAsset(mediaScope, mediaId, hostId, staff.orgId)\n if (!located) return res.status(400).json({ error: 'Choose an image from your media library.' })\n const contentType = String(located.doc['contentType'] ?? '')\n if (!POS_READER_SPLASH_SOURCE_TYPES.includes(contentType)) {\n return res.status(400).json({ error: 'Choose a PNG, JPEG or WebP image.' })\n }\n setting.mediaScope = mediaScope\n setting.mediaId = mediaId\n }\n await terminalConfigRef(hostId).set({ splash: setting }, { merge: true })\n return res.status(200).json(await currentStatus(hostId, org))\n } catch (error) {\n console.error('[pos-reader-splash]', action, error)\n return res.status(500).json({ error: 'The start-up screen could not be updated' })\n }\n}\n"],"names":["createHash","parseMediaCdnScope","formatMediaRef","isMediaCdnPath","MEDIA_CDN_ROUTE","mediaRefFromStorageUrl","parseMediaRef","resolveMediaSrc","checkEntitlement","resolveBrandingProfile","visibleToHost","firebaseAdmin","getOrgForHost","isPosReaderSplashChoice","POS_READER_SPLASH_DEVICE_TYPES","POS_READER_SPLASH_FAMILIES","POS_READER_SPLASH_SOURCE_MAX_BYTES","POS_READER_SPLASH_SOURCE_TYPES","posReaderSplashArtworkProblem","posReaderSplashEffectiveChoice","authorizePosStaff","posRequestBody","PosReaderSplashRenderError","posReaderSplashImageFacts","renderPosReaderSplash","POS_STRIPE_VERSION","posTerminalAvailable","savePosReaderConfiguration","RENDER_VERSION","POS_READER_SPLASH_SETTINGS_ID","firestore","app","terminalConfigRef","hostId","collection","doc","platformSplashRef","posReaderSplashBucket","storage","bucket","process","env","NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET","undefined","readPlatformSplash","snapshot","get","exists","data","platformSplashReady","Boolean","families","storagePath","platformSplashVersion","map","family","id","sha256","join","digest","value","update","cleanString","trim","locateMediaAsset","scopeSegment","mediaId","orgId","scope","test","owned","isOrg","scopeId","String","version","kind","locateSource","stored","ref","rest","slice","length","split","slash","indexOf","address","url","readAssetBytes","asset","mediaCdnServeBlock","mediaStoragePathInScope","blocked","contentSha256","contentHash","objectPath","base","buffer","file","download","FETCH_TIMEOUT_MS","fetchPublicImage","createPinnedDispatcher","resolvePublicIp","pinnedIp","URL","hostname","dispatcher","controller","AbortController","timeout","setTimeout","abort","response","init","redirect","signal","fetch","ok","headers","declared","Number","Buffer","from","arrayBuffer","clearTimeout","close","catch","readSourceBytes","source","workspaceLogoValue","org","whiteLabel","brand","NO_LOGO","NO_IMAGE","planPosReaderSplash","config","platform","productName","setting","choice","effectiveChoice","logoValue","image","mediaScope","platformReady","key","problem","mode","located","loadSharpFactory","loadSharp","drawScreens","sharp","screens","read","large","largeBody","own","body","contentType","bytes","facts","width","height","uploadSplashFile","screen","form","FormData","append","extension","Blob","Uint8Array","type","method","Authorization","STRIPE_SECRET_KEY","json","error","message","ownerOrgOf","owner","applyPosReaderSplash","options","outcome","plan","applied","force","params","deviceType","fileId","deviceTypes","saved","set","splashAppliedKey","splashAppliedAtMs","Date","now","splashProblem","FieldValue","delete","merge","console","splashFailedAtMs","statusOf","available","logoUrl","locationReady","appliedAtMs","currentStatus","result","posReaderSplashHandler","req","res","status","gate","staff","action","updatedAtMs","updatedBy","uid","includes","splash"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/pos-reader-splash.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 { createHash } from 'node:crypto'\nimport { parseMediaCdnScope, type MediaCdnScope } from '@aglyn/aglyn/app-utils/media-cdn-scope'\nimport {\n formatMediaRef,\n isMediaCdnPath,\n MEDIA_CDN_ROUTE,\n mediaRefFromStorageUrl,\n parseMediaRef,\n resolveMediaSrc,\n} from '@aglyn/aglyn/app-utils/media-ref'\nimport { checkEntitlement, resolveBrandingProfile } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport type { PluginEventPayloads } from '@aglyn/aglyn/plugin-manager/plugin-events'\nimport type { PluginJobHostGate } from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgDoc, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport { siteLockdownJobGate } from '@aglyn/tenant-data-admin/server/tenant-write-lockdown'\nimport {\n isPosReaderSplashChoice,\n POS_READER_SPLASH_DEVICE_TYPES,\n POS_READER_SPLASH_FAMILIES,\n POS_READER_SPLASH_SOURCE_MAX_BYTES,\n POS_READER_SPLASH_SOURCE_TYPES,\n posReaderSplashArtworkProblem,\n posReaderSplashEffectiveChoice,\n type PosReaderSplashChoice,\n type PosReaderSplashFamily,\n type PosReaderSplashFamilyId,\n type PosReaderSplashSetting,\n type PosReaderSplashStatus,\n} from '../model/pos-reader-splash'\nimport { authorizePosStaff, posRequestBody } from './pos-auth'\nimport {\n PosReaderSplashRenderError,\n posReaderSplashImageFacts,\n renderPosReaderSplash,\n type RenderedPosReaderSplash,\n} from './pos-reader-splash-render'\nimport { POS_STRIPE_VERSION, posTerminalAvailable } from './pos-stripe'\nimport { savePosReaderConfiguration } from './pos-terminal'\n\n/*==========================================\n * A STORE'S CARD READERS SHOW ITS START-UP SCREEN (AGL-4048).\n *\n * ## Where it lives\n *\n * Readers and Locations are the PLATFORM's (the destination-charge model,\n * `pos-terminal.ts`), one Location per site. The screen is set on that\n * site's one Terminal Configuration, the one reader tipping already uses,\n * per device type (`stripe_s700`, `stripe_s710`, `bbpos_wisepos_e`), from a\n * File uploaded to Stripe with purpose `terminal_reader_splashscreen`.\n *\n * The platform's account-default configuration is NEVER given a screen. A\n * Location without an override inherits it, so an account default would put\n * the platform's brand on a white-label store's readers, which is the one\n * thing the white-label rule forbids. Staff's default screen is applied per\n * Location instead, to the stores that use it.\n *\n * ## What is applied\n *\n * `hosts/{hostId}/terminal/config.splash` holds the store's choice\n * (`model/pos-reader-splash.ts`); the screen applied is described by a KEY\n * built from cheap metadata only: the choice, the platform default's\n * version, the logo's address and its asset's content digest, the picked\n * image's. `splashAppliedKey` records the last key that reached Stripe, so\n * applying again with nothing changed makes no Stripe call at all, and a\n * changed logo, a new staff default or a new choice makes exactly one round\n * of uploads. Every upload and the first configuration write are keyed by\n * content, so a retried apply never makes a second file or configuration.\n *\n * ## When it is applied\n *\n * - when the store's Location is created (its first reader);\n * - when the POS devices card saves a choice, or opens and finds the key\n * stale (a logo changed since);\n * - when staff change the default, for every store with a Location\n * (`pos-reader-splash-admin.ts`);\n * - when a logo is saved on the organization profile or the brand, for\n * every store of that workspace with a Location, once the save has\n * answered: core's `org.logo.changed` event ({@link onOrgLogoChanged});\n * - on the commerce plugin's `pos-reader-splash-refresh` beat, for every\n * store with a Location whose key went stale with nobody opening the\n * card: the backstop for an event that failed, and the only path for a\n * logo's file replaced in the media library ({@link refreshPosReaderSplashes}).\n *\n * Never on the payment path, and never IN FRONT of a logo's save: drawing\n * and uploading takes a second or two, and a reader with an older screen\n * still takes the payment.\n *\n * ## Test mode first\n *\n * Gated by `posTerminalAvailable()`: always in test mode, in live mode only\n * once `STRIPE_TERMINAL_LIVE_ENABLED` is on, like every reader control.\n *=========================================*/\n\n/** Raised when the drawing or the Location changes how keys are built. */\nconst RENDER_VERSION = 'v1'\n\n/** `platformSettings/posReaderSplash`: staff's default screen. */\nexport const POS_READER_SPLASH_SETTINGS_ID = 'posReaderSplash'\n\n/** One family's default screen, as staff uploaded it. */\nexport interface PlatformSplashImage {\n storagePath: string\n sha256: string\n contentType: 'image/png' | 'image/jpeg'\n bytes: number\n uploadedAtMs: number\n uploadedBy?: string\n}\n\nexport interface PlatformSplashDoc {\n families?: Partial<Record<PosReaderSplashFamilyId, PlatformSplashImage>>\n updatedAtMs?: number\n}\n\nconst firestore = () => firebaseAdmin.app().firestore()\n\nexport function terminalConfigRef(hostId: string) {\n return firestore().collection('hosts').doc(hostId).collection('terminal').doc('config')\n}\n\nexport function platformSplashRef() {\n return firestore().collection('platformSettings').doc(POS_READER_SPLASH_SETTINGS_ID)\n}\n\nexport function posReaderSplashBucket() {\n return firebaseAdmin\n .app()\n .storage()\n .bucket(process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || undefined)\n}\n\nexport async function readPlatformSplash(): Promise<PlatformSplashDoc> {\n const snapshot = await platformSplashRef().get()\n return (snapshot.exists ? snapshot.data() : {}) as PlatformSplashDoc\n}\n\n/** The default is usable once the S700/S710 screen is uploaded; the smaller one is drawn from it if absent. */\nexport function platformSplashReady(doc: PlatformSplashDoc): boolean {\n return Boolean(doc.families?.['portrait-large']?.storagePath)\n}\n\nfunction platformSplashVersion(doc: PlatformSplashDoc): string {\n return POS_READER_SPLASH_FAMILIES.map((family) => doc.families?.[family.id]?.sha256 ?? '-').join('.')\n}\n\nconst digest = (value: string | Buffer) => createHash('sha256').update(value).digest('hex')\n\nconst cleanString = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/*==========================================\n * READING A SOURCE IMAGE.\n *\n * A media value is read from STORAGE, never fetched, when it names this\n * site's library or its org's: the document must be live, not private,\n * visible to this site, its scope not locked and the asset not quarantined,\n * and the object path inside the scope's media prefix (the rules the media\n * CDN serves by). An https address outside the libraries is fetched only from\n * a public address, pinned against DNS rebinding, with no redirects, a\n * timeout and a size cap.\n *=========================================*/\n\ninterface LocatedAsset {\n kind: 'asset'\n scope: MediaCdnScope\n scopeSegment: string\n mediaId: string\n doc: Record<string, unknown>\n /** What changes when the asset's bytes do. */\n version: string\n}\n\ninterface LocatedUrl {\n kind: 'url'\n url: string\n version: string\n}\n\ntype LocatedSource = LocatedAsset | LocatedUrl\n\nasync function locateMediaAsset(\n scopeSegment: string,\n mediaId: string,\n hostId: string,\n orgId: string,\n): Promise<LocatedAsset | null> {\n const scope = parseMediaCdnScope(scopeSegment)\n if (!scope || !/^[A-Za-z0-9_-]{1,64}$/.test(mediaId)) return null\n const owned = scope.isOrg ? scope.scopeId === orgId : scope.scopeId === hostId\n if (!owned) return null\n const snapshot = await firestore()\n .collection(scope.isOrg ? 'orgs' : 'hosts')\n .doc(scope.scopeId)\n .collection('media')\n .doc(mediaId)\n .get()\n const doc = (snapshot.exists ? snapshot.data() : null) as Record<string, unknown> | null\n if (!doc || doc['deletedAt'] || doc['private']) return null\n if (scope.isOrg && !visibleToHost(doc['visibleTo'] as string[] | undefined, hostId)) return null\n if (!/^image\\//.test(String(doc['contentType'] ?? ''))) return null\n if (typeof doc['sizeBytes'] === 'number' && doc['sizeBytes'] > POS_READER_SPLASH_SOURCE_MAX_BYTES) return null\n const version =\n cleanString(doc['contentSha256']) ||\n cleanString(doc['contentHash']) ||\n String(doc['updatedAtMs'] ?? doc['sizeBytes'] ?? '')\n return { kind: 'asset', scope, scopeSegment, mediaId, doc, version }\n}\n\n/** Where a stored logo or image value lives, or null when it cannot be read. */\nasync function locateSource(value: string, hostId: string, orgId: string): Promise<LocatedSource | null> {\n const stored = parseMediaRef(value) ? value : mediaRefFromStorageUrl(value)\n const ref = stored ? parseMediaRef(stored) : null\n if (ref) return locateMediaAsset(ref.scope, ref.mediaId, hostId, orgId)\n if (isMediaCdnPath(value)) {\n const rest = value.slice(`${MEDIA_CDN_ROUTE}/`.length).split('?')[0]\n const slash = rest.indexOf('/')\n if (slash <= 0) return null\n return locateMediaAsset(rest.slice(0, slash), rest.slice(slash + 1), hostId, orgId)\n }\n // `isMediaCdnPath` narrows a string it refuses to `never`; the value is still the string.\n const address: string = value as string\n if (/^https:\\/\\//.test(address) && address.length <= 2000) return { kind: 'url', url: address, version: address }\n return null\n}\n\nasync function readAssetBytes(asset: LocatedAsset): Promise<Buffer | null> {\n const { mediaCdnServeBlock, mediaStoragePathInScope } = await import('./pos-reader-splash-server')\n const blocked = await mediaCdnServeBlock(asset.scope, {\n contentSha256: typeof asset.doc['contentSha256'] === 'string' ? (asset.doc['contentSha256'] as string) : undefined,\n contentHash: typeof asset.doc['contentHash'] === 'string' ? (asset.doc['contentHash'] as string) : undefined,\n scopeSegment: asset.scopeSegment,\n mediaId: asset.mediaId,\n })\n if (blocked) return null\n const objectPath = mediaStoragePathInScope({\n storagePath: asset.doc['storagePath'],\n base: `${asset.scope.isOrg ? 'orgs' : 'hosts'}/${asset.scope.scopeId}`,\n mediaId: asset.mediaId,\n })\n const [buffer] = (await posReaderSplashBucket().file(objectPath).download()) as [Buffer]\n return buffer.length > POS_READER_SPLASH_SOURCE_MAX_BYTES ? null : buffer\n}\n\nconst FETCH_TIMEOUT_MS = 8000\n\nasync function fetchPublicImage(url: string): Promise<Buffer | null> {\n const { createPinnedDispatcher, resolvePublicIp } = await import('./pos-reader-splash-server')\n const pinnedIp = await resolvePublicIp(new URL(url).hostname)\n if (!pinnedIp) return null\n const dispatcher = createPinnedDispatcher(pinnedIp)\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n const init = { redirect: 'error' as const, signal: controller.signal, dispatcher }\n const response = await fetch(url, init as RequestInit)\n if (!response.ok) return null\n if (!/^image\\//.test(response.headers.get('content-type') ?? '')) return null\n const declared = Number(response.headers.get('content-length') ?? 0)\n if (declared > POS_READER_SPLASH_SOURCE_MAX_BYTES) return null\n const buffer = Buffer.from(await response.arrayBuffer())\n return buffer.length > POS_READER_SPLASH_SOURCE_MAX_BYTES ? null : buffer\n } catch {\n return null\n } finally {\n clearTimeout(timeout)\n ;(dispatcher as { close?: () => Promise<void> }).close?.().catch(() => undefined)\n }\n}\n\nasync function readSourceBytes(source: LocatedSource): Promise<Buffer | null> {\n return source.kind === 'asset' ? readAssetBytes(source) : fetchPublicImage(source.url)\n}\n\n/*==========================================\n * WHAT A STORE SHOWS.\n *=========================================*/\n\n/**\n * The workspace's own logo: a white-label workspace's brand logo first,\n * then the logo on its organization profile. Never the platform's: the\n * resolved brand profile falls back to the platform's own logo for a\n * workspace without a brand, so its `logoUrl` is not read here.\n */\nexport function workspaceLogoValue(org: Record<string, any> | null, whiteLabel: boolean): string | null {\n const brand = whiteLabel ? cleanString(org?.['brandingProfile']?.['logoUrl']) : ''\n return brand || cleanString(org?.['logoUrl']) || null\n}\n\nexport type SplashSource =\n | { mode: 'platform'; doc: PlatformSplashDoc }\n | { mode: 'logo' | 'artwork'; located: LocatedSource }\n\nexport interface PosReaderSplashPlan {\n choice: PosReaderSplashChoice | null\n effectiveChoice: PosReaderSplashChoice\n whiteLabel: boolean\n productName: string\n platformReady: boolean\n logoValue: string | null\n image: { mediaScope: string; mediaId: string } | null\n /** `none` when the readers show Stripe's standard screen. */\n key: string\n problem: string | null\n source: SplashSource | null\n}\n\nconst NO_LOGO = 'Add a logo to your organization profile to show it on your card readers.'\nconst NO_IMAGE = 'The image picked for your card readers is no longer in your media library. Choose another.'\n\nexport async function planPosReaderSplash(\n hostId: string,\n org: Record<string, any> | null,\n config: Record<string, any> | undefined,\n platform?: PlatformSplashDoc,\n): Promise<PosReaderSplashPlan> {\n const orgId = String(org?.['id'] ?? '')\n const whiteLabel = checkEntitlement(org as any, 'whiteLabel')\n const productName = resolveBrandingProfile(org as any).productName\n const setting = (config?.['splash'] ?? null) as PosReaderSplashSetting | null\n const choice = isPosReaderSplashChoice(setting?.choice) ? setting.choice : null\n const effectiveChoice = posReaderSplashEffectiveChoice(choice, whiteLabel)\n const doc = platform ?? (await readPlatformSplash())\n const logoValue = workspaceLogoValue(org, whiteLabel)\n const image =\n setting?.mediaScope && setting?.mediaId ? { mediaScope: setting.mediaScope, mediaId: setting.mediaId } : null\n const base = {\n choice,\n effectiveChoice,\n whiteLabel,\n productName,\n platformReady: platformSplashReady(doc),\n logoValue,\n image,\n }\n if (effectiveChoice === 'platform') {\n // The white-label rule is in `posReaderSplashEffectiveChoice`; this is\n // the guard behind it, because this branch is the platform's brand.\n if (whiteLabel || !platformSplashReady(doc)) return { ...base, key: 'none', problem: null, source: null }\n return {\n ...base,\n key: `platform:${RENDER_VERSION}:${platformSplashVersion(doc)}`,\n problem: null,\n source: { mode: 'platform', doc },\n }\n }\n if (effectiveChoice === 'logo') {\n const located = logoValue ? await locateSource(logoValue, hostId, orgId) : null\n if (!located) return { ...base, key: 'none', problem: NO_LOGO, source: null }\n return {\n ...base,\n key: `logo:${RENDER_VERSION}:${digest(`${logoValue}|${located.version}`).slice(0, 24)}`,\n problem: null,\n source: { mode: 'logo', located },\n }\n }\n const located = image ? await locateMediaAsset(image.mediaScope, image.mediaId, hostId, orgId) : null\n if (!located) return { ...base, key: 'none', problem: NO_IMAGE, source: null }\n return {\n ...base,\n key: `image:${RENDER_VERSION}:${digest(`${image?.mediaScope}/${image?.mediaId}|${located.version}`).slice(0, 24)}`,\n problem: null,\n source: { mode: 'artwork', located },\n }\n}\n\nasync function loadSharpFactory(): Promise<any> {\n const { loadSharp } = await import('./pos-reader-splash-server')\n return loadSharp()\n}\n\n/** Each family's screen for the plan, ready for Stripe. */\nasync function drawScreens(\n source: SplashSource,\n): Promise<Record<PosReaderSplashFamilyId, RenderedPosReaderSplash>> {\n const sharp = await loadSharpFactory()\n const screens = {} as Record<PosReaderSplashFamilyId, RenderedPosReaderSplash>\n if (source.mode === 'platform') {\n const bucket = posReaderSplashBucket()\n const read = async (image: PlatformSplashImage) =>\n ((await bucket.file(image.storagePath).download()) as [Buffer])[0]\n const large = source.doc.families?.['portrait-large'] as PlatformSplashImage\n const largeBody = await read(large)\n for (const family of POS_READER_SPLASH_FAMILIES) {\n const own = source.doc.families?.[family.id]\n // Staff's own screen for the family is sent as uploaded: it was checked\n // against Stripe's rules for exactly this family then. A family staff\n // left empty is drawn from the S700/S710 screen, the same 9:16.\n screens[family.id] = own?.storagePath\n ? { body: own === large ? largeBody : await read(own), contentType: own.contentType }\n : await renderPosReaderSplash({ source: largeBody, family, mode: 'artwork', sharp })\n }\n return screens\n }\n const bytes = await readSourceBytes(source.located)\n if (!bytes) throw new PosReaderSplashRenderError('That image could not be read.')\n if (source.mode === 'artwork') {\n const facts = await posReaderSplashImageFacts(sharp, bytes)\n const problem = posReaderSplashArtworkProblem({\n contentType: facts?.contentType || null,\n bytes: bytes.length,\n width: facts?.width ?? 0,\n height: facts?.height ?? 0,\n })\n if (problem) throw new PosReaderSplashRenderError(problem)\n }\n for (const family of POS_READER_SPLASH_FAMILIES) {\n screens[family.id] = await renderPosReaderSplash({ source: bytes, family, mode: source.mode, sharp })\n }\n return screens\n}\n\n/** One screen uploaded to Stripe, keyed by its content so a retry makes no second file. */\nasync function uploadSplashFile(\n hostId: string,\n family: PosReaderSplashFamily,\n screen: RenderedPosReaderSplash,\n): Promise<string> {\n const form = new FormData()\n form.append('purpose', 'terminal_reader_splashscreen')\n const extension = screen.contentType === 'image/png' ? 'png' : 'jpg'\n form.append('file', new Blob([new Uint8Array(screen.body)], { type: screen.contentType }), `start-up-${family.id}.${extension}`)\n const response = await fetch('https://files.stripe.com/v1/files', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`,\n 'Stripe-Version': POS_STRIPE_VERSION,\n 'Idempotency-Key': `pos-splash-file:${hostId}:${family.id}:${digest(screen.body).slice(0, 32)}`,\n },\n body: form,\n })\n const body = (await response.json().catch(() => ({}))) as { id?: string; error?: { message?: string } }\n if (!response.ok || !body.id) {\n throw new PosReaderSplashRenderError(body.error?.message || 'Stripe did not accept the start-up screen.')\n }\n return String(body.id)\n}\n\n/**\n * Draws each reader family's screen from the plan's source and uploads it to\n * Stripe: the image work, which needs `sharp`. Runs in the images function\n * on Vercel (`pos-reader-splash-images-route.ts`), and in any process off it.\n */\nexport async function drawAndUploadPosReaderSplash(\n hostId: string,\n source: SplashSource,\n): Promise<Record<PosReaderSplashFamilyId, string>> {\n const screens = await drawScreens(source)\n const fileIds = {} as Record<PosReaderSplashFamilyId, string>\n for (const family of POS_READER_SPLASH_FAMILIES) {\n fileIds[family.id] = await uploadSplashFile(hostId, family, screens[family.id])\n }\n return fileIds\n}\n\n/**\n * Each family's Stripe file for the plan (AGL-4048): drawn here where this\n * process can draw, else by the images function, which draws the plan with\n * the same key. A refusal meant for the store comes back as its own problem.\n */\nasync function posReaderSplashFileIds(\n hostId: string,\n key: string,\n source: SplashSource,\n): Promise<Record<PosReaderSplashFamilyId, string>> {\n const images = await import('./pos-reader-splash-images')\n const origin = images.posReaderSplashImagesOrigin()\n if (!origin) return drawAndUploadPosReaderSplash(hostId, source)\n try {\n const answer = await images.requestPosReaderSplashImages<{ fileIds: Record<PosReaderSplashFamilyId, string> }>(\n origin,\n { op: 'draw', hostId, key },\n )\n return answer.fileIds\n } catch (error) {\n if (error instanceof images.PosReaderSplashImagesRefusal) throw new PosReaderSplashRenderError(error.message)\n throw error\n }\n}\n\n/** The org that owns the site, with its id on it (`planPosReaderSplash` reads it). */\nexport async function ownerOrgOf(hostId: string): Promise<Record<string, any> | null> {\n const owner = await getOrgForHost(hostId).catch(() => null)\n if (!owner?.org) return null\n return { ...(owner.org as Record<string, any>), id: String((owner.org as any).id ?? owner.orgId ?? '') }\n}\n\nexport interface PosReaderSplashApplyResult {\n outcome: 'unchanged' | 'applied' | 'cleared' | 'skipped' | 'failed'\n plan: PosReaderSplashPlan | null\n problem: string | null\n}\n\n/**\n * Puts the store's start-up screen on its readers' configuration when it\n * changed since it was last applied. Never throws: a failure is recorded on\n * the store's terminal document and returned, and the readers keep their\n * previous screen.\n */\nexport async function applyPosReaderSplash(\n hostId: string,\n options: {\n org?: Record<string, any> | null\n platform?: PlatformSplashDoc\n force?: boolean\n /**\n * Leave a screen that failed to apply alone until this long after the\n * failure, when it is still the same screen: a background pass must not\n * draw and upload a logo Stripe keeps refusing on every beat. The card\n * passes none, so opening it always tries again.\n */\n retryFailedAfterMs?: number\n } = {},\n): Promise<PosReaderSplashApplyResult> {\n if (!posTerminalAvailable()) return { outcome: 'skipped', plan: null, problem: null }\n const ref = terminalConfigRef(hostId)\n const config = (await ref.get()).data() as Record<string, any> | undefined\n if (!config?.['stripeLocationId']) return { outcome: 'skipped', plan: null, problem: null }\n const org = options.org !== undefined ? options.org : await ownerOrgOf(hostId)\n const plan = await planPosReaderSplash(hostId, org, config, options.platform)\n const applied = typeof config['splashAppliedKey'] === 'string' ? (config['splashAppliedKey'] as string) : null\n // Nothing to show and nothing ever shown: the readers already show\n // Stripe's standard screen, and no Stripe call is needed to keep it.\n if (plan.key === 'none' && (applied === null || applied === 'none') && !options.force) {\n return { outcome: 'unchanged', plan, problem: plan.problem }\n }\n if (plan.key === applied && !options.force) return { outcome: 'unchanged', plan, problem: plan.problem }\n const failedAtMs = typeof config['splashFailedAtMs'] === 'number' ? (config['splashFailedAtMs'] as number) : 0\n if (\n options.retryFailedAfterMs &&\n !options.force &&\n config['splashFailedKey'] === plan.key &&\n Date.now() - failedAtMs < options.retryFailedAfterMs\n ) {\n const problem = typeof config['splashProblem'] === 'string' ? (config['splashProblem'] as string) : plan.problem\n return { outcome: 'skipped', plan, problem }\n }\n try {\n const params: Record<string, string> = {}\n if (plan.key === 'none' || !plan.source) {\n // An empty value unsets the device's screen on this configuration.\n for (const deviceType of POS_READER_SPLASH_DEVICE_TYPES) params[deviceType] = ''\n } else {\n const fileIds = await posReaderSplashFileIds(hostId, plan.key, plan.source)\n for (const family of POS_READER_SPLASH_FAMILIES) {\n for (const deviceType of family.deviceTypes) params[`${deviceType}[splashscreen]`] = fileIds[family.id]\n }\n }\n const saved = await savePosReaderConfiguration(hostId, params, `splash:${digest(plan.key).slice(0, 24)}`)\n if (!saved.ok) throw new PosReaderSplashRenderError('Stripe did not accept the start-up screen. Try again.')\n await ref.set(\n {\n splashAppliedKey: plan.key,\n splashAppliedAtMs: Date.now(),\n splashProblem: firebaseAdmin.firestore.FieldValue.delete(),\n },\n { merge: true },\n )\n return { outcome: plan.key === 'none' ? 'cleared' : 'applied', plan, problem: plan.problem }\n } catch (error) {\n const problem =\n error instanceof PosReaderSplashRenderError ? error.message : 'The start-up screen could not be applied. Try again.'\n if (!(error instanceof PosReaderSplashRenderError)) console.error('[pos-reader-splash]', hostId, error)\n await ref\n .set({ splashProblem: problem, splashFailedAtMs: Date.now(), splashFailedKey: plan.key }, { merge: true })\n .catch(() => undefined)\n return { outcome: 'failed', plan, problem }\n }\n}\n\n/** How many stores one pass reaches, and how many it works on at once. */\nexport const POS_READER_SPLASH_SWEEP_WINDOW = 400\nconst POS_READER_SPLASH_SWEEP_CONCURRENCY = 4\n\nexport interface PosReaderSplashSweep {\n applied: number\n unchanged: number\n failed: number\n /** Locked stores, and screens still inside their failure's retry wait. */\n skipped: number\n /** More stores have readers than one pass reaches. */\n more: boolean\n}\n\n/**\n * Brings every store with a Location up to date with\n * {@link applyPosReaderSplash}, the call the POS devices card makes: a store\n * whose screen key has not moved costs reads and no Stripe call, and one\n * that moved gets exactly one round of uploads. At most\n * {@link POS_READER_SPLASH_SWEEP_WINDOW} stores a pass.\n */\nexport async function applyPosReaderSplashToStores(\n options: {\n platform?: PlatformSplashDoc\n /** Asked before each store; a locked store is left as it is. */\n isLocked?: (hostId: string) => Promise<boolean>\n retryFailedAfterMs?: number\n } = {},\n): Promise<PosReaderSplashSweep> {\n const counts: PosReaderSplashSweep = { applied: 0, unchanged: 0, failed: 0, skipped: 0, more: false }\n const platform = options.platform ?? (await readPlatformSplash())\n const snapshot = await firestore().collectionGroup('terminal').limit(POS_READER_SPLASH_SWEEP_WINDOW + 1).get()\n const docs = snapshot.docs as Array<{ id: string; ref: { path: string }; get: (field: string) => unknown }>\n const hostIds = docs\n .filter((doc) => doc.id === 'config' && doc.get('stripeLocationId'))\n .map((doc) => doc.ref.path.split('/')[1])\n .filter(Boolean)\n await applyPosReaderSplashQueue(hostIds.slice(0, POS_READER_SPLASH_SWEEP_WINDOW), counts, {\n ...options,\n platform,\n orgOf: ownerOrgOf,\n })\n return { ...counts, more: docs.length > POS_READER_SPLASH_SWEEP_WINDOW }\n}\n\n/** Works through `hostIds` a few at a time, counting each store's outcome into `counts`. */\nasync function applyPosReaderSplashQueue(\n hostIds: string[],\n counts: PosReaderSplashSweep,\n options: {\n platform: PlatformSplashDoc\n orgOf: (hostId: string) => Promise<Record<string, any> | null>\n isLocked?: (hostId: string) => Promise<boolean>\n retryFailedAfterMs?: number\n },\n): Promise<void> {\n const queue = [...hostIds]\n await Promise.all(\n Array.from({ length: POS_READER_SPLASH_SWEEP_CONCURRENCY }, async () => {\n for (let hostId = queue.shift(); hostId; hostId = queue.shift()) {\n if (options.isLocked && (await options.isLocked(hostId))) {\n counts.skipped += 1\n continue\n }\n const result = await applyPosReaderSplash(hostId, {\n org: await options.orgOf(hostId),\n platform: options.platform,\n ...(options.retryFailedAfterMs ? { retryFailedAfterMs: options.retryFailedAfterMs } : {}),\n })\n if (result.outcome === 'applied' || result.outcome === 'cleared') counts.applied += 1\n else if (result.outcome === 'failed') counts.failed += 1\n else if (result.outcome === 'skipped') counts.skipped += 1\n else counts.unchanged += 1\n }\n }),\n )\n}\n\n/** How long a background pass leaves a screen Stripe refused before trying it again. */\nexport const POS_READER_SPLASH_RETRY_FAILED_AFTER_MS = 6 * 60 * 60 * 1000\n\n/**\n * The `pos-reader-splash-refresh` beat (AGL-4048): a logo changed on the\n * organization profile or the white-label brand, or the logo's file replaced\n * in the media library, reaches the store's readers without anybody opening\n * the POS devices card. The screen's key already moves with each of those,\n * so the beat only has to ask; nothing waits on it, and a save never waits\n * on Stripe. Asks the runner's lockdown gate for every store.\n */\nexport async function refreshPosReaderSplashes(gate: {\n isLocked: (hostId: string) => Promise<boolean>\n}): Promise<PosReaderSplashSweep> {\n const idle: PosReaderSplashSweep = { applied: 0, unchanged: 0, failed: 0, skipped: 0, more: false }\n if (!posTerminalAvailable()) return idle\n return applyPosReaderSplashToStores({\n isLocked: (hostId) => gate.isLocked(hostId),\n retryFailedAfterMs: POS_READER_SPLASH_RETRY_FAILED_AFTER_MS,\n })\n}\n\n/**\n * Core's `org.logo.changed` (AGL-4048): a logo saved on the organization\n * profile or the white-label brand reaches the readers of every store of\n * that workspace now, not on the next beat. Raised after the save has\n * answered, so nobody waits on it.\n *\n * {@link applyPosReaderSplash} for each store, the call the POS devices card\n * makes: a store with no Location, or whose screen does not show the logo\n * that moved (a dark-mode logo, a store showing its own image), costs reads\n * and no Stripe call. A store that is locked is left alone, and a screen\n * Stripe refused waits as it does on the beat; the beat, which stays, is\n * the backstop for anything this misses. Never throws.\n */\nexport async function onOrgLogoChanged(\n payload: Pick<PluginEventPayloads['org.logo.changed'], 'orgId'>,\n gate: PluginJobHostGate = siteLockdownJobGate(),\n): Promise<PosReaderSplashSweep> {\n const counts: PosReaderSplashSweep = { applied: 0, unchanged: 0, failed: 0, skipped: 0, more: false }\n const orgId = String(payload.orgId ?? '').trim()\n if (!orgId || !posTerminalAvailable()) return counts\n try {\n const org = await getOrgDoc(orgId)\n if (!org) return counts\n const snapshot = await firestore()\n .collection('hosts')\n .where('orgId', '==', orgId)\n .limit(POS_READER_SPLASH_SWEEP_WINDOW + 1)\n .get()\n const hostIds = (snapshot.docs as Array<{ id: string }>).map((doc) => String(doc.id))\n await applyPosReaderSplashQueue(hostIds.slice(0, POS_READER_SPLASH_SWEEP_WINDOW), counts, {\n platform: await readPlatformSplash(),\n orgOf: async () => ({ ...(org as Record<string, any>), id: orgId }),\n isLocked: (hostId) => gate.isLocked(hostId),\n retryFailedAfterMs: POS_READER_SPLASH_RETRY_FAILED_AFTER_MS,\n })\n return { ...counts, more: hostIds.length > POS_READER_SPLASH_SWEEP_WINDOW }\n } catch (error) {\n console.error('[pos-reader-splash] a changed logo could not reach the readers', orgId, error)\n return counts\n }\n}\n\n/*==========================================\n * `POST /api/commerce/pos-reader-splash`: the POS devices card's setting.\n *\n * status the store's choice and what it shows (re-applies a stale one)\n * save { choice, mediaScope?, mediaId? } — store and apply\n *\n * Gated like a sale (`authorizePosStaff`), as every reader control is.\n *=========================================*/\n\nfunction statusOf(\n plan: PosReaderSplashPlan | null,\n config: Record<string, any> | undefined,\n hostId: string,\n problem: string | null,\n): PosReaderSplashStatus {\n return {\n available: posTerminalAvailable(),\n choice: plan?.choice ?? null,\n effectiveChoice: plan?.effectiveChoice ?? 'platform',\n whiteLabel: plan?.whiteLabel ?? false,\n productName: plan?.productName ?? '',\n platformReady: plan?.platformReady ?? false,\n logoUrl: plan?.logoValue ? resolveMediaSrc(plan.logoValue, { hostId }) ?? null : null,\n image: plan?.image\n ? { ...plan.image, url: resolveMediaSrc(formatMediaRef(plan.image.mediaScope, plan.image.mediaId), { hostId }) ?? null }\n : null,\n locationReady: Boolean(config?.['stripeLocationId']),\n appliedAtMs: typeof config?.['splashAppliedAtMs'] === 'number' ? config['splashAppliedAtMs'] : null,\n problem: problem ?? (typeof config?.['splashProblem'] === 'string' ? config['splashProblem'] : null),\n }\n}\n\nasync function currentStatus(hostId: string, org: Record<string, any> | null): Promise<PosReaderSplashStatus> {\n const result = await applyPosReaderSplash(hostId, { org })\n const config = (await terminalConfigRef(hostId).get()).data() as Record<string, any> | undefined\n const plan = result.plan ?? (await planPosReaderSplash(hostId, org, config))\n return statusOf(plan, config, hostId, result.outcome === 'failed' ? result.problem : plan.problem)\n}\n\nexport const posReaderSplashHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' })\n const body = posRequestBody(req)\n const hostId = String(body['hostId'] ?? '')\n const action = String(body['action'] ?? '')\n // Changing what the readers show is setting them up (AGL-4047); reading it is not.\n const gate = await authorizePosStaff(req, hostId, action === 'save' ? 'posDevices' : undefined)\n if ('error' in gate) return res.status(gate.status).json({ error: gate.error })\n const staff = gate.staff\n const org = staff.org ? { ...staff.org, id: staff.orgId } : null\n try {\n if (action === 'status') return res.status(200).json(await currentStatus(hostId, org))\n if (action !== 'save') return res.status(400).json({ error: 'Unknown action' })\n if (!posTerminalAvailable()) return res.status(409).json({ error: 'Card readers are not available yet.' })\n const choice = body['choice']\n if (!isPosReaderSplashChoice(choice)) return res.status(400).json({ error: 'Choose what your readers show.' })\n const whiteLabel = checkEntitlement(staff.org as any, 'whiteLabel')\n if (choice === 'platform' && whiteLabel) {\n return res.status(400).json({ error: 'Choose your logo or your own image.' })\n }\n const setting: PosReaderSplashSetting = { choice, updatedAtMs: Date.now(), updatedBy: staff.uid }\n if (choice === 'image') {\n const mediaScope = String(body['mediaScope'] ?? '')\n const mediaId = String(body['mediaId'] ?? '')\n const located = await locateMediaAsset(mediaScope, mediaId, hostId, staff.orgId)\n if (!located) return res.status(400).json({ error: 'Choose an image from your media library.' })\n const contentType = String(located.doc['contentType'] ?? '')\n if (!POS_READER_SPLASH_SOURCE_TYPES.includes(contentType)) {\n return res.status(400).json({ error: 'Choose a PNG, JPEG or WebP image.' })\n }\n setting.mediaScope = mediaScope\n setting.mediaId = mediaId\n }\n await terminalConfigRef(hostId).set({ splash: setting }, { merge: true })\n return res.status(200).json(await currentStatus(hostId, org))\n } catch (error) {\n console.error('[pos-reader-splash]', action, error)\n return res.status(500).json({ error: 'The start-up screen could not be updated' })\n }\n}\n"],"names":["createHash","parseMediaCdnScope","formatMediaRef","isMediaCdnPath","MEDIA_CDN_ROUTE","mediaRefFromStorageUrl","parseMediaRef","resolveMediaSrc","checkEntitlement","resolveBrandingProfile","visibleToHost","firebaseAdmin","getOrgDoc","getOrgForHost","siteLockdownJobGate","isPosReaderSplashChoice","POS_READER_SPLASH_DEVICE_TYPES","POS_READER_SPLASH_FAMILIES","POS_READER_SPLASH_SOURCE_MAX_BYTES","POS_READER_SPLASH_SOURCE_TYPES","posReaderSplashArtworkProblem","posReaderSplashEffectiveChoice","authorizePosStaff","posRequestBody","PosReaderSplashRenderError","posReaderSplashImageFacts","renderPosReaderSplash","POS_STRIPE_VERSION","posTerminalAvailable","savePosReaderConfiguration","RENDER_VERSION","POS_READER_SPLASH_SETTINGS_ID","firestore","app","terminalConfigRef","hostId","collection","doc","platformSplashRef","posReaderSplashBucket","storage","bucket","process","env","NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET","undefined","readPlatformSplash","snapshot","get","exists","data","platformSplashReady","Boolean","families","storagePath","platformSplashVersion","map","family","id","sha256","join","digest","value","update","cleanString","trim","locateMediaAsset","scopeSegment","mediaId","orgId","scope","test","owned","isOrg","scopeId","String","version","kind","locateSource","stored","ref","rest","slice","length","split","slash","indexOf","address","url","readAssetBytes","asset","mediaCdnServeBlock","mediaStoragePathInScope","blocked","contentSha256","contentHash","objectPath","base","buffer","file","download","FETCH_TIMEOUT_MS","fetchPublicImage","createPinnedDispatcher","resolvePublicIp","pinnedIp","URL","hostname","dispatcher","controller","AbortController","timeout","setTimeout","abort","response","init","redirect","signal","fetch","ok","headers","declared","Number","Buffer","from","arrayBuffer","clearTimeout","close","catch","readSourceBytes","source","workspaceLogoValue","org","whiteLabel","brand","NO_LOGO","NO_IMAGE","planPosReaderSplash","config","platform","productName","setting","choice","effectiveChoice","logoValue","image","mediaScope","platformReady","key","problem","mode","located","loadSharpFactory","loadSharp","drawScreens","sharp","screens","read","large","largeBody","own","body","contentType","bytes","facts","width","height","uploadSplashFile","screen","form","FormData","append","extension","Blob","Uint8Array","type","method","Authorization","STRIPE_SECRET_KEY","json","error","message","drawAndUploadPosReaderSplash","fileIds","posReaderSplashFileIds","images","origin","posReaderSplashImagesOrigin","answer","requestPosReaderSplashImages","op","PosReaderSplashImagesRefusal","ownerOrgOf","owner","applyPosReaderSplash","options","outcome","plan","applied","force","failedAtMs","retryFailedAfterMs","Date","now","params","deviceType","deviceTypes","saved","set","splashAppliedKey","splashAppliedAtMs","splashProblem","FieldValue","delete","merge","console","splashFailedAtMs","splashFailedKey","POS_READER_SPLASH_SWEEP_WINDOW","POS_READER_SPLASH_SWEEP_CONCURRENCY","applyPosReaderSplashToStores","counts","unchanged","failed","skipped","more","collectionGroup","limit","docs","hostIds","filter","path","applyPosReaderSplashQueue","orgOf","queue","Promise","all","Array","shift","isLocked","result","POS_READER_SPLASH_RETRY_FAILED_AFTER_MS","refreshPosReaderSplashes","gate","idle","onOrgLogoChanged","payload","where","statusOf","available","logoUrl","locationReady","appliedAtMs","currentStatus","posReaderSplashHandler","req","res","status","action","staff","updatedAtMs","updatedBy","uid","includes","splash"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import type { PluginApiHandler } from '@aglyn/aglyn/server';
|
|
18
|
+
import { type PosTerminalAddress, type PosTerminalReader } from './pos-terminal';
|
|
18
19
|
/**
|
|
19
20
|
* `POST /api/commerce/pos-readers` (AGL-3607): the site's Stripe Terminal
|
|
20
21
|
* card readers, from the "Card readers" settings card, and the server-side
|
|
@@ -25,3 +26,31 @@ import type { PluginApiHandler } from '@aglyn/aglyn/server';
|
|
|
25
26
|
* another store is "not on this site", whatever Stripe would say about it.
|
|
26
27
|
*/
|
|
27
28
|
export declare const posReadersHandler: PluginApiHandler;
|
|
29
|
+
/**
|
|
30
|
+
* Registers a reader to a store by the code it shows: the store's Stripe
|
|
31
|
+
* Terminal Location (made from `address` when the store has none), the
|
|
32
|
+
* reader at Stripe, and `hosts/{hostId}/terminalReaders/{id}`. The POS
|
|
33
|
+
* devices card's Add card reader, and the platform's own register setting a
|
|
34
|
+
* reader up for the store of the person who just bought it (AGL-4038).
|
|
35
|
+
*
|
|
36
|
+
* A reader whose serial number was taken when it was sold in person is
|
|
37
|
+
* found on its hardware order, which moves on to Set up (AGL-4038,
|
|
38
|
+
* `pos-hardware-readers.ts`); that never fails the registration.
|
|
39
|
+
*/
|
|
40
|
+
export declare function registerPosTerminalReader(input: {
|
|
41
|
+
hostId: string;
|
|
42
|
+
orgId: string;
|
|
43
|
+
uid: string;
|
|
44
|
+
registrationCode: unknown;
|
|
45
|
+
label?: unknown;
|
|
46
|
+
registerId?: string;
|
|
47
|
+
address?: PosTerminalAddress;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
ok: true;
|
|
50
|
+
id: string;
|
|
51
|
+
reader: PosTerminalReader;
|
|
52
|
+
} | {
|
|
53
|
+
ok: false;
|
|
54
|
+
status: number;
|
|
55
|
+
error: string;
|
|
56
|
+
}>;
|