@aglyn/plugins-commerce 1.0.0-beta.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +10 -0
- package/package.json +57 -0
- package/src/index.d.ts +38 -0
- package/src/index.js +38 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/account.d.ts +31 -0
- package/src/lib/components/account.js +645 -0
- package/src/lib/components/account.js.map +1 -0
- package/src/lib/components/cart.d.ts +38 -0
- package/src/lib/components/cart.js +851 -0
- package/src/lib/components/cart.js.map +1 -0
- package/src/lib/components/commerce-console-page.d.ts +32 -0
- package/src/lib/components/commerce-console-page.js +296 -0
- package/src/lib/components/commerce-console-page.js.map +1 -0
- package/src/lib/components/commerce-console-sections.d.ts +34 -0
- package/src/lib/components/commerce-console-sections.js +62 -0
- package/src/lib/components/commerce-console-sections.js.map +1 -0
- package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
- package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
- package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
- package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
- package/src/lib/components/console/commerce-glance-card.component.js +340 -0
- package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
- package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
- package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
- package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
- package/src/lib/components/console/discounts-card.component.d.ts +14 -0
- package/src/lib/components/console/discounts-card.component.js +443 -0
- package/src/lib/components/console/discounts-card.component.js.map +1 -0
- package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
- package/src/lib/components/console/entitlement-gate.component.js +115 -0
- package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
- package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
- package/src/lib/components/console/gift-cards-card.component.js +379 -0
- package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
- package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
- package/src/lib/components/console/host-coupons-card.component.js +252 -0
- package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
- package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
- package/src/lib/components/console/host-orders-card.component.js +861 -0
- package/src/lib/components/console/host-orders-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.d.ts +14 -0
- package/src/lib/components/console/locations-card.component.js +256 -0
- package/src/lib/components/console/locations-card.component.js.map +1 -0
- package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
- package/src/lib/components/console/member-posts-card.component.js +283 -0
- package/src/lib/components/console/member-posts-card.component.js.map +1 -0
- package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
- package/src/lib/components/console/newest-site-users-card.component.js +126 -0
- package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
- package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
- package/src/lib/components/console/order-detail-dialog.component.js +976 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
- package/src/lib/components/console/paid-media.d.ts +127 -0
- package/src/lib/components/console/paid-media.js +397 -0
- package/src/lib/components/console/paid-media.js.map +1 -0
- package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
- package/src/lib/components/console/payments-settings-card.component.js +295 -0
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
- package/src/lib/components/console/pos-page.component.d.ts +13 -0
- package/src/lib/components/console/pos-page.component.js +916 -0
- package/src/lib/components/console/pos-page.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
- package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
- package/src/lib/components/console/products-hub-card.component.js +1280 -0
- package/src/lib/components/console/products-hub-card.component.js.map +1 -0
- package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
- package/src/lib/components/console/products-hub-zone.component.js +200 -0
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
- package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
- package/src/lib/components/console/recovery-queue-card.component.js +262 -0
- package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/registers-card.component.d.ts +21 -0
- package/src/lib/components/console/registers-card.component.js +296 -0
- package/src/lib/components/console/registers-card.component.js.map +1 -0
- package/src/lib/components/console/reservations-card.component.d.ts +14 -0
- package/src/lib/components/console/reservations-card.component.js +650 -0
- package/src/lib/components/console/reservations-card.component.js.map +1 -0
- package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
- package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
- package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
- package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
- package/src/lib/components/console/shipping-settings-card.component.js +560 -0
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
- package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
- package/src/lib/components/console/stock-movements-card.component.js +333 -0
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
- package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/store-settings-card.component.js +300 -0
- package/src/lib/components/console/store-settings-card.component.js.map +1 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
- package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
- package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
- package/src/lib/components/console/suppliers-card.component.js +328 -0
- package/src/lib/components/console/suppliers-card.component.js.map +1 -0
- package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
- package/src/lib/components/console/tax-settings-card.component.js +473 -0
- package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
- package/src/lib/components/gate.d.ts +39 -0
- package/src/lib/components/gate.js +202 -0
- package/src/lib/components/gate.js.map +1 -0
- package/src/lib/components/gated-video.d.ts +40 -0
- package/src/lib/components/gated-video.js +366 -0
- package/src/lib/components/gated-video.js.map +1 -0
- package/src/lib/components/member-feed.d.ts +32 -0
- package/src/lib/components/member-feed.js +198 -0
- package/src/lib/components/member-feed.js.map +1 -0
- package/src/lib/components/member-recovery.d.ts +35 -0
- package/src/lib/components/member-recovery.js +313 -0
- package/src/lib/components/member-recovery.js.map +1 -0
- package/src/lib/components/member-signin.d.ts +35 -0
- package/src/lib/components/member-signin.js +257 -0
- package/src/lib/components/member-signin.js.map +1 -0
- package/src/lib/components/member-signup.d.ts +34 -0
- package/src/lib/components/member-signup.js +287 -0
- package/src/lib/components/member-signup.js.map +1 -0
- package/src/lib/components/newsletter-signup.d.ts +39 -0
- package/src/lib/components/newsletter-signup.js +229 -0
- package/src/lib/components/newsletter-signup.js.map +1 -0
- package/src/lib/components/product-detail.d.ts +38 -0
- package/src/lib/components/product-detail.js +1022 -0
- package/src/lib/components/product-detail.js.map +1 -0
- package/src/lib/components/product-grid.d.ts +67 -0
- package/src/lib/components/product-grid.js +909 -0
- package/src/lib/components/product-grid.js.map +1 -0
- package/src/lib/components/product-reviews.d.ts +32 -0
- package/src/lib/components/product-reviews.js +349 -0
- package/src/lib/components/product-reviews.js.map +1 -0
- package/src/lib/components/related-products.d.ts +33 -0
- package/src/lib/components/related-products.js +232 -0
- package/src/lib/components/related-products.js.map +1 -0
- package/src/lib/components/reservation-widget.d.ts +33 -0
- package/src/lib/components/reservation-widget.js +418 -0
- package/src/lib/components/reservation-widget.js.map +1 -0
- package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
- package/src/lib/components/storefront-payment-element-fallback.js +51 -0
- package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
- package/src/lib/components/storefront-payment-element.d.ts +78 -0
- package/src/lib/components/storefront-payment-element.js +156 -0
- package/src/lib/components/storefront-payment-element.js.map +1 -0
- package/src/lib/components/wishlist.d.ts +46 -0
- package/src/lib/components/wishlist.js +304 -0
- package/src/lib/components/wishlist.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +18 -0
- package/src/lib/constants/bundle-common.js +18 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/product-filters.d.ts +35 -0
- package/src/lib/constants/product-filters.js +109 -0
- package/src/lib/constants/product-filters.js.map +1 -0
- package/src/lib/model/commerce-cart.d.ts +52 -0
- package/src/lib/model/commerce-cart.js +102 -0
- package/src/lib/model/commerce-cart.js.map +1 -0
- package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
- package/src/lib/model/commerce-connect-transfer.js +231 -0
- package/src/lib/model/commerce-connect-transfer.js.map +1 -0
- package/src/lib/model/commerce-discounts.d.ts +164 -0
- package/src/lib/model/commerce-discounts.js +231 -0
- package/src/lib/model/commerce-discounts.js.map +1 -0
- package/src/lib/model/commerce-dispute.d.ts +124 -0
- package/src/lib/model/commerce-dispute.js +225 -0
- package/src/lib/model/commerce-dispute.js.map +1 -0
- package/src/lib/model/commerce-gift-cards.d.ts +107 -0
- package/src/lib/model/commerce-gift-cards.js +121 -0
- package/src/lib/model/commerce-gift-cards.js.map +1 -0
- package/src/lib/model/commerce-io.d.ts +36 -0
- package/src/lib/model/commerce-io.js +245 -0
- package/src/lib/model/commerce-io.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +1040 -0
- package/src/lib/model/commerce-orders.js +1022 -0
- package/src/lib/model/commerce-orders.js.map +1 -0
- package/src/lib/model/commerce-promotions.d.ts +188 -0
- package/src/lib/model/commerce-promotions.js +199 -0
- package/src/lib/model/commerce-promotions.js.map +1 -0
- package/src/lib/model/commerce-reservations.d.ts +175 -0
- package/src/lib/model/commerce-reservations.js +157 -0
- package/src/lib/model/commerce-reservations.js.map +1 -0
- package/src/lib/model/commerce-shipping.d.ts +316 -0
- package/src/lib/model/commerce-shipping.js +484 -0
- package/src/lib/model/commerce-shipping.js.map +1 -0
- package/src/lib/model/commerce-stock-holds.d.ts +199 -0
- package/src/lib/model/commerce-stock-holds.js +190 -0
- package/src/lib/model/commerce-stock-holds.js.map +1 -0
- package/src/lib/model/commerce-subscription-status.d.ts +67 -0
- package/src/lib/model/commerce-subscription-status.js +76 -0
- package/src/lib/model/commerce-subscription-status.js.map +1 -0
- package/src/lib/model/commerce-tax-decision.d.ts +222 -0
- package/src/lib/model/commerce-tax-decision.js +165 -0
- package/src/lib/model/commerce-tax-decision.js.map +1 -0
- package/src/lib/model/commerce-tax.d.ts +176 -0
- package/src/lib/model/commerce-tax.js +92 -0
- package/src/lib/model/commerce-tax.js.map +1 -0
- package/src/lib/model/commerce.d.ts +551 -0
- package/src/lib/model/commerce.js +739 -0
- package/src/lib/model/commerce.js.map +1 -0
- package/src/lib/model/index.d.ts +40 -0
- package/src/lib/model/index.js +40 -0
- package/src/lib/model/index.js.map +1 -0
- package/src/lib/model/order-figures.d.ts +48 -0
- package/src/lib/model/order-figures.js +74 -0
- package/src/lib/model/order-figures.js.map +1 -0
- package/src/lib/model/plugin-permissions.d.ts +23 -0
- package/src/lib/model/plugin-permissions.js +34 -0
- package/src/lib/model/plugin-permissions.js.map +1 -0
- package/src/lib/model/purchase-analytics.d.ts +186 -0
- package/src/lib/model/purchase-analytics.js +216 -0
- package/src/lib/model/purchase-analytics.js.map +1 -0
- package/src/lib/plugin-config.d.ts +62 -0
- package/src/lib/plugin-config.js +78 -0
- package/src/lib/plugin-config.js.map +1 -0
- package/src/lib/plugin.d.ts +28 -0
- package/src/lib/plugin.js +147 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/billing-webhook.d.ts +26 -0
- package/src/lib/server/billing-webhook.js +4011 -0
- package/src/lib/server/billing-webhook.js.map +1 -0
- package/src/lib/server/cancel-order.d.ts +87 -0
- package/src/lib/server/cancel-order.js +368 -0
- package/src/lib/server/cancel-order.js.map +1 -0
- package/src/lib/server/cart-checkout.d.ts +25 -0
- package/src/lib/server/cart-checkout.js +976 -0
- package/src/lib/server/cart-checkout.js.map +1 -0
- package/src/lib/server/cart-cookie.d.ts +32 -0
- package/src/lib/server/cart-cookie.js +77 -0
- package/src/lib/server/cart-cookie.js.map +1 -0
- package/src/lib/server/cart.d.ts +34 -0
- package/src/lib/server/cart.js +181 -0
- package/src/lib/server/cart.js.map +1 -0
- package/src/lib/server/catalog.d.ts +127 -0
- package/src/lib/server/catalog.js +277 -0
- package/src/lib/server/catalog.js.map +1 -0
- package/src/lib/server/checkout.d.ts +36 -0
- package/src/lib/server/checkout.js +915 -0
- package/src/lib/server/checkout.js.map +1 -0
- package/src/lib/server/connect.d.ts +26 -0
- package/src/lib/server/connect.js +238 -0
- package/src/lib/server/connect.js.map +1 -0
- package/src/lib/server/contact-refund.d.ts +117 -0
- package/src/lib/server/contact-refund.js +196 -0
- package/src/lib/server/contact-refund.js.map +1 -0
- package/src/lib/server/download.d.ts +39 -0
- package/src/lib/server/download.js +206 -0
- package/src/lib/server/download.js.map +1 -0
- package/src/lib/server/draft-order.d.ts +26 -0
- package/src/lib/server/draft-order.js +706 -0
- package/src/lib/server/draft-order.js.map +1 -0
- package/src/lib/server/feed.d.ts +24 -0
- package/src/lib/server/feed.js +59 -0
- package/src/lib/server/feed.js.map +1 -0
- package/src/lib/server/fulfill-order.d.ts +97 -0
- package/src/lib/server/fulfill-order.js +235 -0
- package/src/lib/server/fulfill-order.js.map +1 -0
- package/src/lib/server/gate.d.ts +36 -0
- package/src/lib/server/gate.js +112 -0
- package/src/lib/server/gate.js.map +1 -0
- package/src/lib/server/gift-cards.d.ts +42 -0
- package/src/lib/server/gift-cards.js +219 -0
- package/src/lib/server/gift-cards.js.map +1 -0
- package/src/lib/server/low-stock.d.ts +49 -0
- package/src/lib/server/low-stock.js +60 -0
- package/src/lib/server/low-stock.js.map +1 -0
- package/src/lib/server/manual-tax-rate.d.ts +82 -0
- package/src/lib/server/manual-tax-rate.js +113 -0
- package/src/lib/server/manual-tax-rate.js.map +1 -0
- package/src/lib/server/member-feed.d.ts +24 -0
- package/src/lib/server/member-feed.js +72 -0
- package/src/lib/server/member-feed.js.map +1 -0
- package/src/lib/server/member-name-search.d.ts +37 -0
- package/src/lib/server/member-name-search.js +42 -0
- package/src/lib/server/member-name-search.js.map +1 -0
- package/src/lib/server/member-post.d.ts +23 -0
- package/src/lib/server/member-post.js +166 -0
- package/src/lib/server/member-post.js.map +1 -0
- package/src/lib/server/membership-account.d.ts +37 -0
- package/src/lib/server/membership-account.js +148 -0
- package/src/lib/server/membership-account.js.map +1 -0
- package/src/lib/server/membership-admin-password.d.ts +33 -0
- package/src/lib/server/membership-admin-password.js +202 -0
- package/src/lib/server/membership-admin-password.js.map +1 -0
- package/src/lib/server/membership-content.d.ts +23 -0
- package/src/lib/server/membership-content.js +105 -0
- package/src/lib/server/membership-content.js.map +1 -0
- package/src/lib/server/membership-login.d.ts +19 -0
- package/src/lib/server/membership-login.js +137 -0
- package/src/lib/server/membership-login.js.map +1 -0
- package/src/lib/server/membership-logout.d.ts +19 -0
- package/src/lib/server/membership-logout.js +35 -0
- package/src/lib/server/membership-logout.js.map +1 -0
- package/src/lib/server/membership-recover.d.ts +60 -0
- package/src/lib/server/membership-recover.js +244 -0
- package/src/lib/server/membership-recover.js.map +1 -0
- package/src/lib/server/membership-register.d.ts +22 -0
- package/src/lib/server/membership-register.js +241 -0
- package/src/lib/server/membership-register.js.map +1 -0
- package/src/lib/server/membership-reset.d.ts +26 -0
- package/src/lib/server/membership-reset.js +88 -0
- package/src/lib/server/membership-reset.js.map +1 -0
- package/src/lib/server/membership-wishlist.d.ts +23 -0
- package/src/lib/server/membership-wishlist.js +89 -0
- package/src/lib/server/membership-wishlist.js.map +1 -0
- package/src/lib/server/membership.d.ts +96 -0
- package/src/lib/server/membership.js +222 -0
- package/src/lib/server/membership.js.map +1 -0
- package/src/lib/server/native-checkout.d.ts +170 -0
- package/src/lib/server/native-checkout.js +193 -0
- package/src/lib/server/native-checkout.js.map +1 -0
- package/src/lib/server/newsletter.d.ts +23 -0
- package/src/lib/server/newsletter.js +323 -0
- package/src/lib/server/newsletter.js.map +1 -0
- package/src/lib/server/notify-restock.d.ts +22 -0
- package/src/lib/server/notify-restock.js +84 -0
- package/src/lib/server/notify-restock.js.map +1 -0
- package/src/lib/server/order-analytics.d.ts +134 -0
- package/src/lib/server/order-analytics.js +263 -0
- package/src/lib/server/order-analytics.js.map +1 -0
- package/src/lib/server/order-figures.d.ts +33 -0
- package/src/lib/server/order-figures.js +220 -0
- package/src/lib/server/order-figures.js.map +1 -0
- package/src/lib/server/paid-media-delivery.d.ts +173 -0
- package/src/lib/server/paid-media-delivery.js +212 -0
- package/src/lib/server/paid-media-delivery.js.map +1 -0
- package/src/lib/server/pos-order.d.ts +54 -0
- package/src/lib/server/pos-order.js +1137 -0
- package/src/lib/server/pos-order.js.map +1 -0
- package/src/lib/server/process-abandoned.d.ts +54 -0
- package/src/lib/server/process-abandoned.js +222 -0
- package/src/lib/server/process-abandoned.js.map +1 -0
- package/src/lib/server/process-restock.d.ts +42 -0
- package/src/lib/server/process-restock.js +219 -0
- package/src/lib/server/process-restock.js.map +1 -0
- package/src/lib/server/product-card.d.ts +29 -0
- package/src/lib/server/product-card.js +54 -0
- package/src/lib/server/product-card.js.map +1 -0
- package/src/lib/server/product.d.ts +70 -0
- package/src/lib/server/product.js +105 -0
- package/src/lib/server/product.js.map +1 -0
- package/src/lib/server/promotion-hold.d.ts +144 -0
- package/src/lib/server/promotion-hold.js +174 -0
- package/src/lib/server/promotion-hold.js.map +1 -0
- package/src/lib/server/reconcile-stock.d.ts +106 -0
- package/src/lib/server/reconcile-stock.js +349 -0
- package/src/lib/server/reconcile-stock.js.map +1 -0
- package/src/lib/server/refund.d.ts +45 -0
- package/src/lib/server/refund.js +607 -0
- package/src/lib/server/refund.js.map +1 -0
- package/src/lib/server/related.d.ts +24 -0
- package/src/lib/server/related.js +104 -0
- package/src/lib/server/related.js.map +1 -0
- package/src/lib/server/reservation-availability.d.ts +23 -0
- package/src/lib/server/reservation-availability.js +111 -0
- package/src/lib/server/reservation-availability.js.map +1 -0
- package/src/lib/server/reserve-stock.d.ts +156 -0
- package/src/lib/server/reserve-stock.js +146 -0
- package/src/lib/server/reserve-stock.js.map +1 -0
- package/src/lib/server/reserve.d.ts +25 -0
- package/src/lib/server/reserve.js +426 -0
- package/src/lib/server/reserve.js.map +1 -0
- package/src/lib/server/restock-flag.d.ts +202 -0
- package/src/lib/server/restock-flag.js +449 -0
- package/src/lib/server/restock-flag.js.map +1 -0
- package/src/lib/server/reviews.d.ts +51 -0
- package/src/lib/server/reviews.js +132 -0
- package/src/lib/server/reviews.js.map +1 -0
- package/src/lib/server/site-page-enricher.d.ts +42 -0
- package/src/lib/server/site-page-enricher.js +149 -0
- package/src/lib/server/site-page-enricher.js.map +1 -0
- package/src/lib/server/site-page-resolver.d.ts +26 -0
- package/src/lib/server/site-page-resolver.js +223 -0
- package/src/lib/server/site-page-resolver.js.map +1 -0
- package/src/lib/server/stock-hold.d.ts +127 -0
- package/src/lib/server/stock-hold.js +258 -0
- package/src/lib/server/stock-hold.js.map +1 -0
- package/src/lib/server/storefront-tax-record.d.ts +22 -0
- package/src/lib/server/storefront-tax-record.js +218 -0
- package/src/lib/server/storefront-tax-record.js.map +1 -0
- package/src/lib/server/storefront-tax.d.ts +197 -0
- package/src/lib/server/storefront-tax.js +245 -0
- package/src/lib/server/storefront-tax.js.map +1 -0
- package/src/lib/server/stream.d.ts +25 -0
- package/src/lib/server/stream.js +191 -0
- package/src/lib/server/stream.js.map +1 -0
- package/src/lib/server/subscription-portal.d.ts +24 -0
- package/src/lib/server/subscription-portal.js +91 -0
- package/src/lib/server/subscription-portal.js.map +1 -0
- package/src/lib/server/supplier-outbox.d.ts +190 -0
- package/src/lib/server/supplier-outbox.js +342 -0
- package/src/lib/server/supplier-outbox.js.map +1 -0
- package/src/lib/server/supplier-update.d.ts +23 -0
- package/src/lib/server/supplier-update.js +289 -0
- package/src/lib/server/supplier-update.js.map +1 -0
- package/src/lib/server/tax-profile.d.ts +29 -0
- package/src/lib/server/tax-profile.js +40 -0
- package/src/lib/server/tax-profile.js.map +1 -0
- package/src/lib/server.d.ts +32 -0
- package/src/lib/server.js +311 -0
- package/src/lib/server.js.map +1 -0
- package/src/lib/site.d.ts +27 -0
- package/src/lib/site.js +134 -0
- package/src/lib/site.js.map +1 -0
- package/src/lib/utils/escape-html.d.ts +41 -0
- package/src/lib/utils/escape-html.js +41 -0
- package/src/lib/utils/escape-html.js.map +1 -0
- package/src/lib/utils/generate-preset-id.d.ts +19 -0
- package/src/lib/utils/generate-preset-id.js +25 -0
- package/src/lib/utils/generate-preset-id.js.map +1 -0
- package/src/lib/utils/member-continue.d.ts +45 -0
- package/src/lib/utils/member-continue.js +49 -0
- package/src/lib/utils/member-continue.js.map +1 -0
- package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
- package/src/lib/utils/use-storefront-purchase-event.js +142 -0
- package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { PluginApiHandler } from '@aglyn/aglyn/server';
|
|
18
|
+
/**
|
|
19
|
+
* The figures a storefront `purchase` needs, for one completed order
|
|
20
|
+
* (AGL-1641).
|
|
21
|
+
*
|
|
22
|
+
* ## Why the client cannot compute this itself
|
|
23
|
+
*
|
|
24
|
+
* The obvious cheap design is to stash the cart at `begin_checkout` and replay
|
|
25
|
+
* it on return, with no endpoint at all. It produces the wrong number: the
|
|
26
|
+
* shopper picks their SHIPPING and may enter a promotion code on Stripe's
|
|
27
|
+
* page, after the cart snapshot was taken, so a replayed cart understates
|
|
28
|
+
* every order that carries shipping. The authoritative totals only exist after
|
|
29
|
+
* the webhook has written the order, which is why this reads the order.
|
|
30
|
+
*
|
|
31
|
+
* ## What authorises the read
|
|
32
|
+
*
|
|
33
|
+
* The Stripe Checkout Session id, which is also the order doc id. It is
|
|
34
|
+
* high-entropy and unguessable, it is handed only to the buyer — Stripe puts
|
|
35
|
+
* it in the `success_url` — and it is scoped here to the host that owns the
|
|
36
|
+
* order, so one storefront's id cannot address another's. This is the same
|
|
37
|
+
* bearer-by-opaque-id shape as the `download` and `subscription-portal`
|
|
38
|
+
* routes.
|
|
39
|
+
*
|
|
40
|
+
* It is still a public read, so the response is a PROJECTION built by
|
|
41
|
+
* `toStorefrontPurchaseSource`, never the order document: no email, no name,
|
|
42
|
+
* no shipping or billing address, and not our `feeCents` either. A buyer
|
|
43
|
+
* learns only what they themselves just bought.
|
|
44
|
+
*
|
|
45
|
+
* ## The webhook race
|
|
46
|
+
*
|
|
47
|
+
* The shopper can return from Stripe before the `checkout.session.completed`
|
|
48
|
+
* delivery has been processed, in which case the order does not exist yet.
|
|
49
|
+
* That is answered with 404 and a `retryable` flag rather than a synthesised
|
|
50
|
+
* order — the client polls briefly. Reporting a purchase we cannot yet read
|
|
51
|
+
* would mean inventing the value.
|
|
52
|
+
*
|
|
53
|
+
* Never cached: an order that 404s during the race must not have that 404
|
|
54
|
+
* stored in front of it, which is the AGL negative-cache shape that has bitten
|
|
55
|
+
* host lookups before.
|
|
56
|
+
*
|
|
57
|
+
* ## Subscriptions answer from the INVOICE, not from an order (AGL-1746)
|
|
58
|
+
*
|
|
59
|
+
* A subscription sale writes no order document — deliberately, on three
|
|
60
|
+
* independent pieces of evidence gathered in AGL-1732 — so the lookup above
|
|
61
|
+
* missed forever on every one of them. The merchant's own GA4 property
|
|
62
|
+
* therefore showed traffic and `begin_checkout` for the subscription product
|
|
63
|
+
* and then no `purchase` at all, which does not read as "we do not measure
|
|
64
|
+
* this": it reads as a 100% checkout abandonment rate on the product, an
|
|
65
|
+
* authoritative-looking number that is wrong.
|
|
66
|
+
*
|
|
67
|
+
* The data to answer with exists now. AGL-1732 records the sale on
|
|
68
|
+
* `subscriptions/{stripeSubscriptionId}` carrying the originating
|
|
69
|
+
* `checkoutSessionId`, and AGL-1743 records every paid invoice beneath it,
|
|
70
|
+
* including the opening one — kept explicitly so the ledger has no hole where
|
|
71
|
+
* cycle 1 belongs, even though that cycle is deliberately not re-counted into
|
|
72
|
+
* lifetime value.
|
|
73
|
+
*
|
|
74
|
+
* The opening INVOICE is what answers, for two reasons:
|
|
75
|
+
*
|
|
76
|
+
* - Its id is a natural `transaction_id`. It is Stripe's own id for the money
|
|
77
|
+
* that moved, it is unique per cycle, and it is stable — the same sale
|
|
78
|
+
* resolves to the same invoice on every poll, so a shopper who refreshes the
|
|
79
|
+
* return page cannot produce a second `purchase` under a different id. GA4
|
|
80
|
+
* de-duplicates on `transaction_id`, and that only protects us if the id is
|
|
81
|
+
* deterministic.
|
|
82
|
+
* - Its `lineItems` and `totals` were built by
|
|
83
|
+
* `computeSubscriptionInvoiceOrder`, which is the helper that knows an
|
|
84
|
+
* invoice is NOT a Checkout Session: AGL-1743 found invoices carry no
|
|
85
|
+
* `total_details` whatsoever, that tax is `tax` or `total_taxes` by API
|
|
86
|
+
* version, discount is `total_discount_amounts[]`, and the fee is a real
|
|
87
|
+
* `application_fee_amount`. Reading the stored figures means this route
|
|
88
|
+
* inherits all of that instead of re-deriving it against the wrong shape.
|
|
89
|
+
*
|
|
90
|
+
* `value` needs no special-casing here, and that is the point of answering in
|
|
91
|
+
* the same wire shape: `toStorefrontPurchaseSource` and
|
|
92
|
+
* `buildStorefrontPurchaseParams` already implement the AGL-1641 storefront
|
|
93
|
+
* rule, which is the INVERSE of the marketplace one. On a tenant storefront
|
|
94
|
+
* the MERCHANT is the seller, so Aglyn's fee is their cost of sale rather than
|
|
95
|
+
* a deduction from it and is NOT subtracted; tax is money held for the state
|
|
96
|
+
* and is excluded, with no GA4 `tax` param sent beside an ex-tax `value`.
|
|
97
|
+
* Getting that backwards would show every merchant a figure a few percent of
|
|
98
|
+
* their real revenue.
|
|
99
|
+
*
|
|
100
|
+
* ## Renewals do NOT send a `purchase` — and could not
|
|
101
|
+
*
|
|
102
|
+
* A recurring revenue event per cycle is arguable on the merits, and the
|
|
103
|
+
* argument against it on the merits is real: `purchase` is what GA4's
|
|
104
|
+
* acquisition and ROAS reporting is terminated by, so firing one every month
|
|
105
|
+
* would credit a single acquisition to its campaign twelve times over and
|
|
106
|
+
* inflate return on ad spend by the subscriber's whole lifetime.
|
|
107
|
+
*
|
|
108
|
+
* But it does not come down to that, because this seam cannot carry a renewal
|
|
109
|
+
* at all. This purchase is CLIENT-side by design: the hit is sent by
|
|
110
|
+
* `use-storefront-purchase-event.ts` through the merchant's own `gtag`, loaded
|
|
111
|
+
* with `host.analytics.gaMeasurementId`. A renewal happens months later with
|
|
112
|
+
* no browser anywhere in it. Sending one would require the Measurement
|
|
113
|
+
* Protocol against the merchant's property, which needs a per-host API secret
|
|
114
|
+
* that this product does not collect and has nowhere to store — the same
|
|
115
|
+
* conclusion `use-storefront-purchase-event.ts` reached from the other
|
|
116
|
+
* direction. `ga4-measurement-protocol.ts` is not that channel: it holds one
|
|
117
|
+
* global `GA4_MEASUREMENT_ID`/`GA4_API_SECRET` pair, which is AGLYN's property
|
|
118
|
+
* and reports our revenue, not the merchant's.
|
|
119
|
+
*
|
|
120
|
+
* So the storefront reports the subscription's FIRST payment, once, and stops
|
|
121
|
+
* — mirroring AGL-1743's own decision not to re-count the opening invoice
|
|
122
|
+
* anywhere the checkout session had already been counted.
|
|
123
|
+
*
|
|
124
|
+
* ## Why both lookups run
|
|
125
|
+
*
|
|
126
|
+
* A Checkout Session id does not say whether it was a one-time or a
|
|
127
|
+
* subscription mode session, so a miss on the order genuinely might be either
|
|
128
|
+
* the webhook race or a subscription. The subscription lookups therefore run
|
|
129
|
+
* on every order miss. Both are single-field equality queries with `limit(1)`,
|
|
130
|
+
* which Firestore serves from the automatic single-field indexes it maintains
|
|
131
|
+
* for every field — there is no composite index here to create, and none to
|
|
132
|
+
* probe.
|
|
133
|
+
*/
|
|
134
|
+
export declare const orderAnalyticsHandler: PluginApiHandler;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { stripeIdIsTestMode } from "@aglyn/aglyn/app-utils/stripe-deployment-mode";
|
|
18
|
+
import * as CommerceModel from "../model/index.js";
|
|
19
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
20
|
+
import { toStorefrontPurchaseSource } from "../model/purchase-analytics.js";
|
|
21
|
+
/** Stripe Checkout Session ids: `cs_` + live/test prefix + base58-ish body. */ const SESSION_ID = /^cs_[A-Za-z0-9_]{8,255}$/;
|
|
22
|
+
/**
|
|
23
|
+
* Stripe's `billing_reason` for the invoice a subscription OPENS with, as
|
|
24
|
+
* opposed to the `subscription_cycle` ones that follow it (AGL-1743 stores
|
|
25
|
+
* both under the subscription).
|
|
26
|
+
*/ const OPENING_INVOICE_REASON = 'subscription_create';
|
|
27
|
+
/**
|
|
28
|
+
* The figures a storefront `purchase` needs, for one completed order
|
|
29
|
+
* (AGL-1641).
|
|
30
|
+
*
|
|
31
|
+
* ## Why the client cannot compute this itself
|
|
32
|
+
*
|
|
33
|
+
* The obvious cheap design is to stash the cart at `begin_checkout` and replay
|
|
34
|
+
* it on return, with no endpoint at all. It produces the wrong number: the
|
|
35
|
+
* shopper picks their SHIPPING and may enter a promotion code on Stripe's
|
|
36
|
+
* page, after the cart snapshot was taken, so a replayed cart understates
|
|
37
|
+
* every order that carries shipping. The authoritative totals only exist after
|
|
38
|
+
* the webhook has written the order, which is why this reads the order.
|
|
39
|
+
*
|
|
40
|
+
* ## What authorises the read
|
|
41
|
+
*
|
|
42
|
+
* The Stripe Checkout Session id, which is also the order doc id. It is
|
|
43
|
+
* high-entropy and unguessable, it is handed only to the buyer — Stripe puts
|
|
44
|
+
* it in the `success_url` — and it is scoped here to the host that owns the
|
|
45
|
+
* order, so one storefront's id cannot address another's. This is the same
|
|
46
|
+
* bearer-by-opaque-id shape as the `download` and `subscription-portal`
|
|
47
|
+
* routes.
|
|
48
|
+
*
|
|
49
|
+
* It is still a public read, so the response is a PROJECTION built by
|
|
50
|
+
* `toStorefrontPurchaseSource`, never the order document: no email, no name,
|
|
51
|
+
* no shipping or billing address, and not our `feeCents` either. A buyer
|
|
52
|
+
* learns only what they themselves just bought.
|
|
53
|
+
*
|
|
54
|
+
* ## The webhook race
|
|
55
|
+
*
|
|
56
|
+
* The shopper can return from Stripe before the `checkout.session.completed`
|
|
57
|
+
* delivery has been processed, in which case the order does not exist yet.
|
|
58
|
+
* That is answered with 404 and a `retryable` flag rather than a synthesised
|
|
59
|
+
* order — the client polls briefly. Reporting a purchase we cannot yet read
|
|
60
|
+
* would mean inventing the value.
|
|
61
|
+
*
|
|
62
|
+
* Never cached: an order that 404s during the race must not have that 404
|
|
63
|
+
* stored in front of it, which is the AGL negative-cache shape that has bitten
|
|
64
|
+
* host lookups before.
|
|
65
|
+
*
|
|
66
|
+
* ## Subscriptions answer from the INVOICE, not from an order (AGL-1746)
|
|
67
|
+
*
|
|
68
|
+
* A subscription sale writes no order document — deliberately, on three
|
|
69
|
+
* independent pieces of evidence gathered in AGL-1732 — so the lookup above
|
|
70
|
+
* missed forever on every one of them. The merchant's own GA4 property
|
|
71
|
+
* therefore showed traffic and `begin_checkout` for the subscription product
|
|
72
|
+
* and then no `purchase` at all, which does not read as "we do not measure
|
|
73
|
+
* this": it reads as a 100% checkout abandonment rate on the product, an
|
|
74
|
+
* authoritative-looking number that is wrong.
|
|
75
|
+
*
|
|
76
|
+
* The data to answer with exists now. AGL-1732 records the sale on
|
|
77
|
+
* `subscriptions/{stripeSubscriptionId}` carrying the originating
|
|
78
|
+
* `checkoutSessionId`, and AGL-1743 records every paid invoice beneath it,
|
|
79
|
+
* including the opening one — kept explicitly so the ledger has no hole where
|
|
80
|
+
* cycle 1 belongs, even though that cycle is deliberately not re-counted into
|
|
81
|
+
* lifetime value.
|
|
82
|
+
*
|
|
83
|
+
* The opening INVOICE is what answers, for two reasons:
|
|
84
|
+
*
|
|
85
|
+
* - Its id is a natural `transaction_id`. It is Stripe's own id for the money
|
|
86
|
+
* that moved, it is unique per cycle, and it is stable — the same sale
|
|
87
|
+
* resolves to the same invoice on every poll, so a shopper who refreshes the
|
|
88
|
+
* return page cannot produce a second `purchase` under a different id. GA4
|
|
89
|
+
* de-duplicates on `transaction_id`, and that only protects us if the id is
|
|
90
|
+
* deterministic.
|
|
91
|
+
* - Its `lineItems` and `totals` were built by
|
|
92
|
+
* `computeSubscriptionInvoiceOrder`, which is the helper that knows an
|
|
93
|
+
* invoice is NOT a Checkout Session: AGL-1743 found invoices carry no
|
|
94
|
+
* `total_details` whatsoever, that tax is `tax` or `total_taxes` by API
|
|
95
|
+
* version, discount is `total_discount_amounts[]`, and the fee is a real
|
|
96
|
+
* `application_fee_amount`. Reading the stored figures means this route
|
|
97
|
+
* inherits all of that instead of re-deriving it against the wrong shape.
|
|
98
|
+
*
|
|
99
|
+
* `value` needs no special-casing here, and that is the point of answering in
|
|
100
|
+
* the same wire shape: `toStorefrontPurchaseSource` and
|
|
101
|
+
* `buildStorefrontPurchaseParams` already implement the AGL-1641 storefront
|
|
102
|
+
* rule, which is the INVERSE of the marketplace one. On a tenant storefront
|
|
103
|
+
* the MERCHANT is the seller, so Aglyn's fee is their cost of sale rather than
|
|
104
|
+
* a deduction from it and is NOT subtracted; tax is money held for the state
|
|
105
|
+
* and is excluded, with no GA4 `tax` param sent beside an ex-tax `value`.
|
|
106
|
+
* Getting that backwards would show every merchant a figure a few percent of
|
|
107
|
+
* their real revenue.
|
|
108
|
+
*
|
|
109
|
+
* ## Renewals do NOT send a `purchase` — and could not
|
|
110
|
+
*
|
|
111
|
+
* A recurring revenue event per cycle is arguable on the merits, and the
|
|
112
|
+
* argument against it on the merits is real: `purchase` is what GA4's
|
|
113
|
+
* acquisition and ROAS reporting is terminated by, so firing one every month
|
|
114
|
+
* would credit a single acquisition to its campaign twelve times over and
|
|
115
|
+
* inflate return on ad spend by the subscriber's whole lifetime.
|
|
116
|
+
*
|
|
117
|
+
* But it does not come down to that, because this seam cannot carry a renewal
|
|
118
|
+
* at all. This purchase is CLIENT-side by design: the hit is sent by
|
|
119
|
+
* `use-storefront-purchase-event.ts` through the merchant's own `gtag`, loaded
|
|
120
|
+
* with `host.analytics.gaMeasurementId`. A renewal happens months later with
|
|
121
|
+
* no browser anywhere in it. Sending one would require the Measurement
|
|
122
|
+
* Protocol against the merchant's property, which needs a per-host API secret
|
|
123
|
+
* that this product does not collect and has nowhere to store — the same
|
|
124
|
+
* conclusion `use-storefront-purchase-event.ts` reached from the other
|
|
125
|
+
* direction. `ga4-measurement-protocol.ts` is not that channel: it holds one
|
|
126
|
+
* global `GA4_MEASUREMENT_ID`/`GA4_API_SECRET` pair, which is AGLYN's property
|
|
127
|
+
* and reports our revenue, not the merchant's.
|
|
128
|
+
*
|
|
129
|
+
* So the storefront reports the subscription's FIRST payment, once, and stops
|
|
130
|
+
* — mirroring AGL-1743's own decision not to re-count the opening invoice
|
|
131
|
+
* anywhere the checkout session had already been counted.
|
|
132
|
+
*
|
|
133
|
+
* ## Why both lookups run
|
|
134
|
+
*
|
|
135
|
+
* A Checkout Session id does not say whether it was a one-time or a
|
|
136
|
+
* subscription mode session, so a miss on the order genuinely might be either
|
|
137
|
+
* the webhook race or a subscription. The subscription lookups therefore run
|
|
138
|
+
* on every order miss. Both are single-field equality queries with `limit(1)`,
|
|
139
|
+
* which Firestore serves from the automatic single-field indexes it maintains
|
|
140
|
+
* for every field — there is no composite index here to create, and none to
|
|
141
|
+
* probe.
|
|
142
|
+
*/ export const orderAnalyticsHandler = async (req, res)=>{
|
|
143
|
+
var _req_query_hostId, _req_query_sessionId;
|
|
144
|
+
const hostId = String((_req_query_hostId = req.query.hostId) != null ? _req_query_hostId : '');
|
|
145
|
+
const sessionId = String((_req_query_sessionId = req.query.sessionId) != null ? _req_query_sessionId : '');
|
|
146
|
+
if (!hostId || !sessionId) {
|
|
147
|
+
return res.status(400).json({
|
|
148
|
+
error: 'Missing hostId or sessionId'
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Shape-checked before it reaches Firestore: a document id is a path
|
|
152
|
+
// segment, and an unvalidated one is how a lookup becomes a traversal.
|
|
153
|
+
if (!SESSION_ID.test(sessionId)) {
|
|
154
|
+
return res.status(400).json({
|
|
155
|
+
error: 'Invalid sessionId'
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// A REHEARSAL MUST NOT REACH THE MERCHANT'S OWN ANALYTICS.
|
|
159
|
+
//
|
|
160
|
+
// This endpoint hands the browser a `purchase` payload that
|
|
161
|
+
// `use-storefront-purchase-event.ts` pushes through the MERCHANT's `gtag`,
|
|
162
|
+
// into the MERCHANT's GA4 property. A smoke-test checkout therefore writes a
|
|
163
|
+
// fake sale into a real merchant's funnel — the same pollution as the
|
|
164
|
+
// revenue cards, except it lands somewhere Aglyn does not control and
|
|
165
|
+
// cannot later correct.
|
|
166
|
+
//
|
|
167
|
+
// Refused HERE rather than at the webhook, because this is not a webhook.
|
|
168
|
+
// The billing route's AGL-2040 livemode gate already refuses cross-mode
|
|
169
|
+
// events, so every per-sale effect driven by it — the buyer receipt, the
|
|
170
|
+
// merchant notification, the dropship purchase order — is covered. This
|
|
171
|
+
// route is a plain GET the storefront calls on its own success page, so it
|
|
172
|
+
// reads an order that already exists and is reached by no gate at all.
|
|
173
|
+
//
|
|
174
|
+
// The SESSION ID is the discriminator and it covers both branches below: a
|
|
175
|
+
// Checkout Session id states its mode (`cs_test_…`), while the invoice id
|
|
176
|
+
// the subscription branch reports on does NOT, so checking the invoice
|
|
177
|
+
// would miss every recurring sale.
|
|
178
|
+
//
|
|
179
|
+
// 409, matching the "Not payable" refusals below: the client retries only a
|
|
180
|
+
// 404 and treats everything else as terminal, so this fires nothing and
|
|
181
|
+
// polls nothing.
|
|
182
|
+
//
|
|
183
|
+
// FAILING TOWARDS FIRING. An unrecognised id is live: suppressing a real
|
|
184
|
+
// sale would corrupt a merchant's funnel in the one direction they can
|
|
185
|
+
// never spot, exactly as counting one would corrupt their revenue.
|
|
186
|
+
if (stripeIdIsTestMode(sessionId)) {
|
|
187
|
+
return res.status(409).json({
|
|
188
|
+
error: 'Not payable',
|
|
189
|
+
reason: 'test-mode'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
var _invoice_get, _invoice_data;
|
|
194
|
+
const hostRef = firebaseAdmin.app().firestore().collection('hosts').doc(hostId);
|
|
195
|
+
const snapshot = await hostRef.collection('orders').doc(sessionId).get();
|
|
196
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
197
|
+
if (snapshot.exists) {
|
|
198
|
+
var _snapshot_data;
|
|
199
|
+
const order = (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {};
|
|
200
|
+
// Only a PAID order is a purchase. A session can be written in another
|
|
201
|
+
// state by the draft/POS paths, and reporting one as revenue would put a
|
|
202
|
+
// sale in the merchant's report that has not happened.
|
|
203
|
+
if (order.status !== 'paid') {
|
|
204
|
+
return res.status(409).json({
|
|
205
|
+
error: 'Not payable'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// The RECORDED fact as well as the id. An order the webhook
|
|
209
|
+
// stamped `livemode: false` is a rehearsal whatever its id looks like,
|
|
210
|
+
// and this is the stronger of the two signals.
|
|
211
|
+
if (CommerceModel.orderIsTestMode(_extends({}, order, {
|
|
212
|
+
$id: snapshot.id
|
|
213
|
+
}))) {
|
|
214
|
+
return res.status(409).json({
|
|
215
|
+
error: 'Not payable',
|
|
216
|
+
reason: 'test-mode'
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return res.status(200).json(toStorefrontPurchaseSource(snapshot.id, order));
|
|
220
|
+
}
|
|
221
|
+
// No order. That is either the webhook race above, or a SUBSCRIPTION sale,
|
|
222
|
+
// which records no order at all (AGL-1746). The subscription carries the
|
|
223
|
+
// session that created it.
|
|
224
|
+
const subscriptions = await hostRef.collection('subscriptions').where('checkoutSessionId', '==', sessionId).limit(1).get();
|
|
225
|
+
const subscription = subscriptions.docs[0];
|
|
226
|
+
if (!subscription) {
|
|
227
|
+
// Retryable: the race, or an id that was never ours.
|
|
228
|
+
return res.status(404).json({
|
|
229
|
+
error: 'Not found',
|
|
230
|
+
retryable: true
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
// The money, rather than the sale record: the opening invoice is what was
|
|
234
|
+
// actually collected, and its id is the transaction id.
|
|
235
|
+
const invoices = await subscription.ref.collection('invoices').where('billingReason', '==', OPENING_INVOICE_REASON).limit(1).get();
|
|
236
|
+
const invoice = invoices.docs[0];
|
|
237
|
+
if (!invoice) {
|
|
238
|
+
// `checkout.session.completed` has landed and `invoice.paid` has not —
|
|
239
|
+
// still the race, one webhook further along.
|
|
240
|
+
return res.status(404).json({
|
|
241
|
+
error: 'Not found',
|
|
242
|
+
retryable: true
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
// A TRIAL opens on a $0 invoice. Nothing was charged, so there is no
|
|
246
|
+
// revenue to report; this is the subscription's form of "not payable", and
|
|
247
|
+
// it is terminal rather than retryable because it will never become true
|
|
248
|
+
// for THIS invoice.
|
|
249
|
+
if (!(Number((_invoice_get = invoice.get('paidCents')) != null ? _invoice_get : 0) > 0)) {
|
|
250
|
+
return res.status(409).json({
|
|
251
|
+
error: 'Not payable'
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return res.status(200).json(toStorefrontPurchaseSource(invoice.id, (_invoice_data = invoice.data()) != null ? _invoice_data : {}));
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error(error);
|
|
257
|
+
return res.status(500).json({
|
|
258
|
+
error: 'Lookup failed'
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
//# sourceMappingURL=order-analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/order-analytics.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 { stripeIdIsTestMode } from '@aglyn/aglyn/app-utils/stripe-deployment-mode'\nimport * as CommerceModel from '../model'\nimport type { PluginApiHandler } from '@aglyn/aglyn/server'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { toStorefrontPurchaseSource } from '../model/purchase-analytics'\n\n/** Stripe Checkout Session ids: `cs_` + live/test prefix + base58-ish body. */\nconst SESSION_ID = /^cs_[A-Za-z0-9_]{8,255}$/\n\n/**\n * Stripe's `billing_reason` for the invoice a subscription OPENS with, as\n * opposed to the `subscription_cycle` ones that follow it (AGL-1743 stores\n * both under the subscription).\n */\nconst OPENING_INVOICE_REASON = 'subscription_create'\n\n/**\n * The figures a storefront `purchase` needs, for one completed order\n * (AGL-1641).\n *\n * ## Why the client cannot compute this itself\n *\n * The obvious cheap design is to stash the cart at `begin_checkout` and replay\n * it on return, with no endpoint at all. It produces the wrong number: the\n * shopper picks their SHIPPING and may enter a promotion code on Stripe's\n * page, after the cart snapshot was taken, so a replayed cart understates\n * every order that carries shipping. The authoritative totals only exist after\n * the webhook has written the order, which is why this reads the order.\n *\n * ## What authorises the read\n *\n * The Stripe Checkout Session id, which is also the order doc id. It is\n * high-entropy and unguessable, it is handed only to the buyer — Stripe puts\n * it in the `success_url` — and it is scoped here to the host that owns the\n * order, so one storefront's id cannot address another's. This is the same\n * bearer-by-opaque-id shape as the `download` and `subscription-portal`\n * routes.\n *\n * It is still a public read, so the response is a PROJECTION built by\n * `toStorefrontPurchaseSource`, never the order document: no email, no name,\n * no shipping or billing address, and not our `feeCents` either. A buyer\n * learns only what they themselves just bought.\n *\n * ## The webhook race\n *\n * The shopper can return from Stripe before the `checkout.session.completed`\n * delivery has been processed, in which case the order does not exist yet.\n * That is answered with 404 and a `retryable` flag rather than a synthesised\n * order — the client polls briefly. Reporting a purchase we cannot yet read\n * would mean inventing the value.\n *\n * Never cached: an order that 404s during the race must not have that 404\n * stored in front of it, which is the AGL negative-cache shape that has bitten\n * host lookups before.\n *\n * ## Subscriptions answer from the INVOICE, not from an order (AGL-1746)\n *\n * A subscription sale writes no order document — deliberately, on three\n * independent pieces of evidence gathered in AGL-1732 — so the lookup above\n * missed forever on every one of them. The merchant's own GA4 property\n * therefore showed traffic and `begin_checkout` for the subscription product\n * and then no `purchase` at all, which does not read as \"we do not measure\n * this\": it reads as a 100% checkout abandonment rate on the product, an\n * authoritative-looking number that is wrong.\n *\n * The data to answer with exists now. AGL-1732 records the sale on\n * `subscriptions/{stripeSubscriptionId}` carrying the originating\n * `checkoutSessionId`, and AGL-1743 records every paid invoice beneath it,\n * including the opening one — kept explicitly so the ledger has no hole where\n * cycle 1 belongs, even though that cycle is deliberately not re-counted into\n * lifetime value.\n *\n * The opening INVOICE is what answers, for two reasons:\n *\n * - Its id is a natural `transaction_id`. It is Stripe's own id for the money\n * that moved, it is unique per cycle, and it is stable — the same sale\n * resolves to the same invoice on every poll, so a shopper who refreshes the\n * return page cannot produce a second `purchase` under a different id. GA4\n * de-duplicates on `transaction_id`, and that only protects us if the id is\n * deterministic.\n * - Its `lineItems` and `totals` were built by\n * `computeSubscriptionInvoiceOrder`, which is the helper that knows an\n * invoice is NOT a Checkout Session: AGL-1743 found invoices carry no\n * `total_details` whatsoever, that tax is `tax` or `total_taxes` by API\n * version, discount is `total_discount_amounts[]`, and the fee is a real\n * `application_fee_amount`. Reading the stored figures means this route\n * inherits all of that instead of re-deriving it against the wrong shape.\n *\n * `value` needs no special-casing here, and that is the point of answering in\n * the same wire shape: `toStorefrontPurchaseSource` and\n * `buildStorefrontPurchaseParams` already implement the AGL-1641 storefront\n * rule, which is the INVERSE of the marketplace one. On a tenant storefront\n * the MERCHANT is the seller, so Aglyn's fee is their cost of sale rather than\n * a deduction from it and is NOT subtracted; tax is money held for the state\n * and is excluded, with no GA4 `tax` param sent beside an ex-tax `value`.\n * Getting that backwards would show every merchant a figure a few percent of\n * their real revenue.\n *\n * ## Renewals do NOT send a `purchase` — and could not\n *\n * A recurring revenue event per cycle is arguable on the merits, and the\n * argument against it on the merits is real: `purchase` is what GA4's\n * acquisition and ROAS reporting is terminated by, so firing one every month\n * would credit a single acquisition to its campaign twelve times over and\n * inflate return on ad spend by the subscriber's whole lifetime.\n *\n * But it does not come down to that, because this seam cannot carry a renewal\n * at all. This purchase is CLIENT-side by design: the hit is sent by\n * `use-storefront-purchase-event.ts` through the merchant's own `gtag`, loaded\n * with `host.analytics.gaMeasurementId`. A renewal happens months later with\n * no browser anywhere in it. Sending one would require the Measurement\n * Protocol against the merchant's property, which needs a per-host API secret\n * that this product does not collect and has nowhere to store — the same\n * conclusion `use-storefront-purchase-event.ts` reached from the other\n * direction. `ga4-measurement-protocol.ts` is not that channel: it holds one\n * global `GA4_MEASUREMENT_ID`/`GA4_API_SECRET` pair, which is AGLYN's property\n * and reports our revenue, not the merchant's.\n *\n * So the storefront reports the subscription's FIRST payment, once, and stops\n * — mirroring AGL-1743's own decision not to re-count the opening invoice\n * anywhere the checkout session had already been counted.\n *\n * ## Why both lookups run\n *\n * A Checkout Session id does not say whether it was a one-time or a\n * subscription mode session, so a miss on the order genuinely might be either\n * the webhook race or a subscription. The subscription lookups therefore run\n * on every order miss. Both are single-field equality queries with `limit(1)`,\n * which Firestore serves from the automatic single-field indexes it maintains\n * for every field — there is no composite index here to create, and none to\n * probe.\n */\nexport const orderAnalyticsHandler: PluginApiHandler = async (req, res) => {\n const hostId = String(req.query.hostId ?? '')\n const sessionId = String(req.query.sessionId ?? '')\n if (!hostId || !sessionId) {\n return res.status(400).json({ error: 'Missing hostId or sessionId' })\n }\n // Shape-checked before it reaches Firestore: a document id is a path\n // segment, and an unvalidated one is how a lookup becomes a traversal.\n if (!SESSION_ID.test(sessionId)) {\n return res.status(400).json({ error: 'Invalid sessionId' })\n }\n // A REHEARSAL MUST NOT REACH THE MERCHANT'S OWN ANALYTICS.\n //\n // This endpoint hands the browser a `purchase` payload that\n // `use-storefront-purchase-event.ts` pushes through the MERCHANT's `gtag`,\n // into the MERCHANT's GA4 property. A smoke-test checkout therefore writes a\n // fake sale into a real merchant's funnel — the same pollution as the\n // revenue cards, except it lands somewhere Aglyn does not control and\n // cannot later correct.\n //\n // Refused HERE rather than at the webhook, because this is not a webhook.\n // The billing route's AGL-2040 livemode gate already refuses cross-mode\n // events, so every per-sale effect driven by it — the buyer receipt, the\n // merchant notification, the dropship purchase order — is covered. This\n // route is a plain GET the storefront calls on its own success page, so it\n // reads an order that already exists and is reached by no gate at all.\n //\n // The SESSION ID is the discriminator and it covers both branches below: a\n // Checkout Session id states its mode (`cs_test_…`), while the invoice id\n // the subscription branch reports on does NOT, so checking the invoice\n // would miss every recurring sale.\n //\n // 409, matching the \"Not payable\" refusals below: the client retries only a\n // 404 and treats everything else as terminal, so this fires nothing and\n // polls nothing.\n //\n // FAILING TOWARDS FIRING. An unrecognised id is live: suppressing a real\n // sale would corrupt a merchant's funnel in the one direction they can\n // never spot, exactly as counting one would corrupt their revenue.\n if (stripeIdIsTestMode(sessionId)) {\n return res.status(409).json({ error: 'Not payable', reason: 'test-mode' })\n }\n try {\n const hostRef = firebaseAdmin\n .app()\n .firestore()\n .collection('hosts')\n .doc(hostId)\n const snapshot = await hostRef.collection('orders').doc(sessionId).get()\n\n res.setHeader('Cache-Control', 'no-store')\n\n if (snapshot.exists) {\n const order = (snapshot.data() ?? {}) as any\n // Only a PAID order is a purchase. A session can be written in another\n // state by the draft/POS paths, and reporting one as revenue would put a\n // sale in the merchant's report that has not happened.\n if (order.status !== 'paid') {\n return res.status(409).json({ error: 'Not payable' })\n }\n // The RECORDED fact as well as the id. An order the webhook\n // stamped `livemode: false` is a rehearsal whatever its id looks like,\n // and this is the stronger of the two signals.\n if (CommerceModel.orderIsTestMode({ ...order, $id: snapshot.id })) {\n return res.status(409).json({ error: 'Not payable', reason: 'test-mode' })\n }\n return res\n .status(200)\n .json(toStorefrontPurchaseSource(snapshot.id, order))\n }\n\n // No order. That is either the webhook race above, or a SUBSCRIPTION sale,\n // which records no order at all (AGL-1746). The subscription carries the\n // session that created it.\n const subscriptions = await hostRef\n .collection('subscriptions')\n .where('checkoutSessionId', '==', sessionId)\n .limit(1)\n .get()\n const subscription = subscriptions.docs[0]\n if (!subscription) {\n // Retryable: the race, or an id that was never ours.\n return res.status(404).json({ error: 'Not found', retryable: true })\n }\n // The money, rather than the sale record: the opening invoice is what was\n // actually collected, and its id is the transaction id.\n const invoices = await subscription.ref\n .collection('invoices')\n .where('billingReason', '==', OPENING_INVOICE_REASON)\n .limit(1)\n .get()\n const invoice = invoices.docs[0]\n if (!invoice) {\n // `checkout.session.completed` has landed and `invoice.paid` has not —\n // still the race, one webhook further along.\n return res.status(404).json({ error: 'Not found', retryable: true })\n }\n // A TRIAL opens on a $0 invoice. Nothing was charged, so there is no\n // revenue to report; this is the subscription's form of \"not payable\", and\n // it is terminal rather than retryable because it will never become true\n // for THIS invoice.\n if (!(Number(invoice.get('paidCents') ?? 0) > 0)) {\n return res.status(409).json({ error: 'Not payable' })\n }\n return res\n .status(200)\n .json(\n toStorefrontPurchaseSource(invoice.id, (invoice.data() ?? {}) as any),\n )\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Lookup failed' })\n }\n}\n"],"names":["stripeIdIsTestMode","CommerceModel","firebaseAdmin","toStorefrontPurchaseSource","SESSION_ID","OPENING_INVOICE_REASON","orderAnalyticsHandler","req","res","hostId","String","query","sessionId","status","json","error","test","reason","invoice","hostRef","app","firestore","collection","doc","snapshot","get","setHeader","exists","order","data","orderIsTestMode","$id","id","subscriptions","where","limit","subscription","docs","retryable","invoices","ref","Number","console"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type PluginFigureReader } from '@aglyn/aglyn/plugin-manager/plugin-figures';
|
|
18
|
+
/**
|
|
19
|
+
* The store's sales figures for another plugin to read (AGL-2915): what the
|
|
20
|
+
* Analytics tab's card shows, as tables on the `plugin-figures` seam. The
|
|
21
|
+
* insight job reads them by id and never reads an order.
|
|
22
|
+
*
|
|
23
|
+
* A table carries sums and counts and product names — never a buyer, an
|
|
24
|
+
* address or an order. Sold under `commerceAnalytics`, the entitlement the
|
|
25
|
+
* card is sold under.
|
|
26
|
+
*/
|
|
27
|
+
type Firestore = FirebaseFirestore.Firestore;
|
|
28
|
+
/** Orders one window reads; a store past it is told its figures read low. */
|
|
29
|
+
export declare const ORDER_FIGURES_WINDOW_CEILING = 1000;
|
|
30
|
+
export declare function orderFigureReaders(firestore: () => Firestore): PluginFigureReader[];
|
|
31
|
+
/** Registers the sales readers from the console surface, where insight jobs run. */
|
|
32
|
+
export declare function registerOrderFigureReaders(firestore: () => Firestore): void;
|
|
33
|
+
export {};
|