@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,220 @@
|
|
|
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 { PLUGIN_FIGURE_MAX_ROWS, pluginFigureChange, pluginFigureWindows, registerPluginFigureReader } from "@aglyn/aglyn/plugin-manager/plugin-figures";
|
|
18
|
+
import { BUNDLE_ID } from "../constants/bundle-common.js";
|
|
19
|
+
import { orderWindowFigures, productSales } from "../model/order-figures.js";
|
|
20
|
+
/** Orders one window reads; a store past it is told its figures read low. */ export const ORDER_FIGURES_WINDOW_CEILING = 1000;
|
|
21
|
+
const WINDOWS = [
|
|
22
|
+
7,
|
|
23
|
+
14,
|
|
24
|
+
30,
|
|
25
|
+
90
|
|
26
|
+
];
|
|
27
|
+
const SOURCE = {
|
|
28
|
+
label: 'Store analytics',
|
|
29
|
+
path: 'products/analytics'
|
|
30
|
+
};
|
|
31
|
+
async function ordersBetween(firestore, hostId, startMs, endMs) {
|
|
32
|
+
// `createdAtMs` is the field every order writer stamps and the one the
|
|
33
|
+
// orders group is indexed on; range and order on it need no composite index.
|
|
34
|
+
const snapshot = await firestore.collection('hosts').doc(hostId).collection('orders').where('createdAtMs', '>=', startMs).where('createdAtMs', '<', endMs).orderBy('createdAtMs', 'desc').limit(ORDER_FIGURES_WINDOW_CEILING + 1).get();
|
|
35
|
+
const orders = snapshot.docs.map((doc)=>{
|
|
36
|
+
var _doc_data;
|
|
37
|
+
return _extends({}, (_doc_data = doc.data()) != null ? _doc_data : {}, {
|
|
38
|
+
$id: doc.id
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
orders: orders.slice(0, ORDER_FIGURES_WINDOW_CEILING),
|
|
43
|
+
truncated: orders.length > ORDER_FIGURES_WINDOW_CEILING
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const dollars = (cents)=>Math.round(cents) / 100;
|
|
47
|
+
function ceilingNote(truncated) {
|
|
48
|
+
return truncated ? [
|
|
49
|
+
`The store took more than ${ORDER_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} orders in a window, so its figures are summed over the most recent ${ORDER_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} and read low.`
|
|
50
|
+
] : [];
|
|
51
|
+
}
|
|
52
|
+
function refusal(request) {
|
|
53
|
+
if (!request.hostId) return {
|
|
54
|
+
ok: false,
|
|
55
|
+
status: 400,
|
|
56
|
+
error: 'Open a site to read its sales'
|
|
57
|
+
};
|
|
58
|
+
if (!WINDOWS.includes(request.days)) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
status: 400,
|
|
62
|
+
error: 'That window is not one sales are read over'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
export function orderFigureReaders(firestore) {
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
id: 'commerce.sales',
|
|
71
|
+
label: 'Sales',
|
|
72
|
+
description: 'The store’s revenue, orders and average order over the window and the window before it, with the change in revenue and in orders. Pending, canceled and test orders are left out, and refunds come off.',
|
|
73
|
+
scope: 'site',
|
|
74
|
+
windows: WINDOWS,
|
|
75
|
+
feature: 'commerceAnalytics',
|
|
76
|
+
read: async (request)=>{
|
|
77
|
+
const refused = refusal(request);
|
|
78
|
+
if (refused) return refused;
|
|
79
|
+
const hostId = request.hostId;
|
|
80
|
+
const { current, previous } = pluginFigureWindows(request.now, request.days);
|
|
81
|
+
const [now, before] = await Promise.all([
|
|
82
|
+
ordersBetween(firestore(), hostId, current.startMs, current.endMs),
|
|
83
|
+
ordersBetween(firestore(), hostId, previous.startMs, previous.endMs)
|
|
84
|
+
]);
|
|
85
|
+
const a = orderWindowFigures(now.orders, current.startMs, current.endMs);
|
|
86
|
+
const b = orderWindowFigures(before.orders, previous.startMs, previous.endMs);
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
table: {
|
|
90
|
+
title: 'Sales',
|
|
91
|
+
source: SOURCE,
|
|
92
|
+
period: {
|
|
93
|
+
from: current.from,
|
|
94
|
+
to: current.to,
|
|
95
|
+
days: request.days
|
|
96
|
+
},
|
|
97
|
+
columns: [
|
|
98
|
+
{
|
|
99
|
+
key: 'window',
|
|
100
|
+
label: 'Window',
|
|
101
|
+
kind: 'text'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: 'revenue',
|
|
105
|
+
label: 'Revenue',
|
|
106
|
+
kind: 'money',
|
|
107
|
+
currency: 'USD'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: 'orders',
|
|
111
|
+
label: 'Orders',
|
|
112
|
+
kind: 'count'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
key: 'averageOrder',
|
|
116
|
+
label: 'Average order',
|
|
117
|
+
kind: 'money',
|
|
118
|
+
currency: 'USD'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
key: 'revenueChange',
|
|
122
|
+
label: 'Revenue change',
|
|
123
|
+
kind: 'change'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'ordersChange',
|
|
127
|
+
label: 'Orders change',
|
|
128
|
+
kind: 'change'
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
rows: [
|
|
132
|
+
{
|
|
133
|
+
window: `${current.from} to ${current.to}`,
|
|
134
|
+
revenue: dollars(a.revenueCents),
|
|
135
|
+
orders: a.orders,
|
|
136
|
+
averageOrder: dollars(a.averageCents),
|
|
137
|
+
revenueChange: pluginFigureChange(a.revenueCents, b.revenueCents),
|
|
138
|
+
ordersChange: pluginFigureChange(a.orders, b.orders)
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
window: `${previous.from} to ${previous.to}`,
|
|
142
|
+
revenue: dollars(b.revenueCents),
|
|
143
|
+
orders: b.orders,
|
|
144
|
+
averageOrder: dollars(b.averageCents),
|
|
145
|
+
revenueChange: null,
|
|
146
|
+
ordersChange: null
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
omitted: 0,
|
|
150
|
+
notes: ceilingNote(now.truncated || before.truncated)
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 'commerce.products',
|
|
157
|
+
label: 'Top products',
|
|
158
|
+
description: 'The products that brought in the most over the window, with units sold and line revenue.',
|
|
159
|
+
scope: 'site',
|
|
160
|
+
windows: WINDOWS,
|
|
161
|
+
feature: 'commerceAnalytics',
|
|
162
|
+
read: async (request)=>{
|
|
163
|
+
const refused = refusal(request);
|
|
164
|
+
if (refused) return refused;
|
|
165
|
+
const { current } = pluginFigureWindows(request.now, request.days);
|
|
166
|
+
const window = await ordersBetween(firestore(), request.hostId, current.startMs, current.endMs);
|
|
167
|
+
const sales = productSales(window.orders);
|
|
168
|
+
return {
|
|
169
|
+
ok: true,
|
|
170
|
+
table: {
|
|
171
|
+
title: 'Top products',
|
|
172
|
+
source: SOURCE,
|
|
173
|
+
period: {
|
|
174
|
+
from: current.from,
|
|
175
|
+
to: current.to,
|
|
176
|
+
days: request.days
|
|
177
|
+
},
|
|
178
|
+
columns: [
|
|
179
|
+
{
|
|
180
|
+
key: 'product',
|
|
181
|
+
label: 'Product',
|
|
182
|
+
kind: 'text'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
key: 'units',
|
|
186
|
+
label: 'Units',
|
|
187
|
+
kind: 'count'
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: 'revenue',
|
|
191
|
+
label: 'Line revenue',
|
|
192
|
+
kind: 'money',
|
|
193
|
+
currency: 'USD'
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
rows: sales.slice(0, PLUGIN_FIGURE_MAX_ROWS).map((entry)=>({
|
|
197
|
+
product: entry.name,
|
|
198
|
+
units: entry.units,
|
|
199
|
+
revenue: dollars(entry.cents)
|
|
200
|
+
})),
|
|
201
|
+
omitted: Math.max(0, sales.length - PLUGIN_FIGURE_MAX_ROWS),
|
|
202
|
+
notes: [
|
|
203
|
+
'Line revenue is each line’s price times its quantity, before discounts, shipping and tax.',
|
|
204
|
+
...ceilingNote(window.truncated)
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
/** Registers the sales readers from the console surface, where insight jobs run. */ export function registerOrderFigureReaders(firestore) {
|
|
213
|
+
for (const reader of orderFigureReaders(firestore)){
|
|
214
|
+
registerPluginFigureReader(reader, {
|
|
215
|
+
pluginId: BUNDLE_ID
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//# sourceMappingURL=order-figures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/server/order-figures.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PLUGIN_FIGURE_MAX_ROWS,\n pluginFigureChange,\n pluginFigureWindows,\n registerPluginFigureReader,\n type PluginFigureReader,\n type PluginFigureRequest,\n} from '@aglyn/aglyn/plugin-manager/plugin-figures'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport {\n orderWindowFigures,\n productSales,\n type OrderFigureSource,\n} from '../model/order-figures'\n\n/**\n * The store's sales figures for another plugin to read (AGL-2915): what the\n * Analytics tab's card shows, as tables on the `plugin-figures` seam. The\n * insight job reads them by id and never reads an order.\n *\n * A table carries sums and counts and product names — never a buyer, an\n * address or an order. Sold under `commerceAnalytics`, the entitlement the\n * card is sold under.\n */\n\ntype Firestore = FirebaseFirestore.Firestore\n\n/** Orders one window reads; a store past it is told its figures read low. */\nexport const ORDER_FIGURES_WINDOW_CEILING = 1_000\n\nconst WINDOWS: readonly number[] = [7, 14, 30, 90]\n\nconst SOURCE = { label: 'Store analytics', path: 'products/analytics' }\n\nasync function ordersBetween(\n firestore: Firestore,\n hostId: string,\n startMs: number,\n endMs: number,\n): Promise<{ orders: OrderFigureSource[]; truncated: boolean }> {\n // `createdAtMs` is the field every order writer stamps and the one the\n // orders group is indexed on; range and order on it need no composite index.\n const snapshot = await firestore\n .collection('hosts')\n .doc(hostId)\n .collection('orders')\n .where('createdAtMs', '>=', startMs)\n .where('createdAtMs', '<', endMs)\n .orderBy('createdAtMs', 'desc')\n .limit(ORDER_FIGURES_WINDOW_CEILING + 1)\n .get()\n const orders = snapshot.docs.map((doc) => ({ ...(doc.data() ?? {}), $id: doc.id }) as OrderFigureSource)\n return {\n orders: orders.slice(0, ORDER_FIGURES_WINDOW_CEILING),\n truncated: orders.length > ORDER_FIGURES_WINDOW_CEILING,\n }\n}\n\nconst dollars = (cents: number): number => Math.round(cents) / 100\n\nfunction ceilingNote(truncated: boolean): string[] {\n return truncated\n ? [\n `The store took more than ${ORDER_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} orders in a window, so its figures are summed over the most recent ${ORDER_FIGURES_WINDOW_CEILING.toLocaleString('en-US')} and read low.`,\n ]\n : []\n}\n\nfunction refusal(request: PluginFigureRequest) {\n if (!request.hostId) return { ok: false as const, status: 400 as const, error: 'Open a site to read its sales' }\n if (!WINDOWS.includes(request.days)) {\n return { ok: false as const, status: 400 as const, error: 'That window is not one sales are read over' }\n }\n return null\n}\n\nexport function orderFigureReaders(firestore: () => Firestore): PluginFigureReader[] {\n return [\n {\n id: 'commerce.sales',\n label: 'Sales',\n description:\n 'The store’s revenue, orders and average order over the window and the window before it, with the change in revenue and in orders. Pending, canceled and test orders are left out, and refunds come off.',\n scope: 'site',\n windows: WINDOWS,\n feature: 'commerceAnalytics',\n read: async (request) => {\n const refused = refusal(request)\n if (refused) return refused\n const hostId = request.hostId as string\n const { current, previous } = pluginFigureWindows(request.now, request.days)\n const [now, before] = await Promise.all([\n ordersBetween(firestore(), hostId, current.startMs, current.endMs),\n ordersBetween(firestore(), hostId, previous.startMs, previous.endMs),\n ])\n const a = orderWindowFigures(now.orders, current.startMs, current.endMs)\n const b = orderWindowFigures(before.orders, previous.startMs, previous.endMs)\n return {\n ok: true,\n table: {\n title: 'Sales',\n source: SOURCE,\n period: { from: current.from, to: current.to, days: request.days },\n columns: [\n { key: 'window', label: 'Window', kind: 'text' },\n { key: 'revenue', label: 'Revenue', kind: 'money', currency: 'USD' },\n { key: 'orders', label: 'Orders', kind: 'count' },\n { key: 'averageOrder', label: 'Average order', kind: 'money', currency: 'USD' },\n { key: 'revenueChange', label: 'Revenue change', kind: 'change' },\n { key: 'ordersChange', label: 'Orders change', kind: 'change' },\n ],\n rows: [\n {\n window: `${current.from} to ${current.to}`,\n revenue: dollars(a.revenueCents),\n orders: a.orders,\n averageOrder: dollars(a.averageCents),\n revenueChange: pluginFigureChange(a.revenueCents, b.revenueCents),\n ordersChange: pluginFigureChange(a.orders, b.orders),\n },\n {\n window: `${previous.from} to ${previous.to}`,\n revenue: dollars(b.revenueCents),\n orders: b.orders,\n averageOrder: dollars(b.averageCents),\n revenueChange: null,\n ordersChange: null,\n },\n ],\n omitted: 0,\n notes: ceilingNote(now.truncated || before.truncated),\n },\n }\n },\n },\n {\n id: 'commerce.products',\n label: 'Top products',\n description: 'The products that brought in the most over the window, with units sold and line revenue.',\n scope: 'site',\n windows: WINDOWS,\n feature: 'commerceAnalytics',\n read: async (request) => {\n const refused = refusal(request)\n if (refused) return refused\n const { current } = pluginFigureWindows(request.now, request.days)\n const window = await ordersBetween(firestore(), request.hostId as string, current.startMs, current.endMs)\n const sales = productSales(window.orders)\n return {\n ok: true,\n table: {\n title: 'Top products',\n source: SOURCE,\n period: { from: current.from, to: current.to, days: request.days },\n columns: [\n { key: 'product', label: 'Product', kind: 'text' },\n { key: 'units', label: 'Units', kind: 'count' },\n { key: 'revenue', label: 'Line revenue', kind: 'money', currency: 'USD' },\n ],\n rows: sales\n .slice(0, PLUGIN_FIGURE_MAX_ROWS)\n .map((entry) => ({ product: entry.name, units: entry.units, revenue: dollars(entry.cents) })),\n omitted: Math.max(0, sales.length - PLUGIN_FIGURE_MAX_ROWS),\n notes: [\n 'Line revenue is each line’s price times its quantity, before discounts, shipping and tax.',\n ...ceilingNote(window.truncated),\n ],\n },\n }\n },\n },\n ]\n}\n\n/** Registers the sales readers from the console surface, where insight jobs run. */\nexport function registerOrderFigureReaders(firestore: () => Firestore): void {\n for (const reader of orderFigureReaders(firestore)) {\n registerPluginFigureReader(reader, { pluginId: BUNDLE_ID })\n }\n}\n"],"names":["PLUGIN_FIGURE_MAX_ROWS","pluginFigureChange","pluginFigureWindows","registerPluginFigureReader","BUNDLE_ID","orderWindowFigures","productSales","ORDER_FIGURES_WINDOW_CEILING","WINDOWS","SOURCE","label","path","ordersBetween","firestore","hostId","startMs","endMs","snapshot","collection","doc","where","orderBy","limit","get","orders","docs","map","data","$id","id","slice","truncated","length","dollars","cents","Math","round","ceilingNote","toLocaleString","refusal","request","ok","status","error","includes","days","orderFigureReaders","description","scope","windows","feature","read","refused","current","previous","now","before","Promise","all","a","b","table","title","source","period","from","to","columns","key","kind","currency","rows","window","revenue","revenueCents","averageOrder","averageCents","revenueChange","ordersChange","omitted","notes","sales","entry","product","name","units","max","registerOrderFigureReaders","reader","pluginId"],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
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 MediaDeliveryProvider } from '@aglyn/aglyn/plugin-manager/media-delivery-provider';
|
|
18
|
+
/**
|
|
19
|
+
* Turning a URL stored on a product into a link a buyer may follow (AGL-2814).
|
|
20
|
+
*
|
|
21
|
+
* A product's paid media — its members videos — is stored as whatever the
|
|
22
|
+
* author's picker wrote: a media reference, a CDN path, a raw Storage download
|
|
23
|
+
* URL, or a hotlink somebody typed. `parsePaidMediaSource` says which of those
|
|
24
|
+
* a value is. The commerce routes verify who is entitled and then redirect;
|
|
25
|
+
* this module decides WHERE they may redirect, and its whole job is that the
|
|
26
|
+
* answer is never a URL that outlives the purchase.
|
|
27
|
+
*
|
|
28
|
+
* ## The rules, in the order they are applied
|
|
29
|
+
*
|
|
30
|
+
* 1. **A library asset is delivered only when it is PRIVATE**, as a CDN URL
|
|
31
|
+
* signed with {@link mintMediaSignature}. The CDN refuses a private asset on
|
|
32
|
+
* every path without an unexpired signature, which is what makes the link
|
|
33
|
+
* die. A public asset is refused here instead of redirected to: its URL
|
|
34
|
+
* works for anyone forever, so handing it to a buyer is the leak itself.
|
|
35
|
+
* 2. **A Storage download URL is never redirected to.** Its token lives as
|
|
36
|
+
* long as the object. When the object belongs to a library asset, rule 1
|
|
37
|
+
* applies to that asset. When no asset owns it (a legacy object, a derived
|
|
38
|
+
* rendition file), it gets a V4 signed read URL with the same bounded
|
|
39
|
+
* lifetime. When it is not in this platform's bucket, or not inside the
|
|
40
|
+
* site's own library or its org's, it is refused.
|
|
41
|
+
* 3. **Only the requesting site's own libraries are signed.** A product is
|
|
42
|
+
* author data. Signing whatever scope it names would let one site's author
|
|
43
|
+
* mint working links to another org's private files, so a host scope must
|
|
44
|
+
* be this site and an org scope must be this site's org, and the signed
|
|
45
|
+
* scope is always qualified with this site so the CDN's `visibleTo` check
|
|
46
|
+
* runs against the site actually selling it.
|
|
47
|
+
* 4. **A hotlink to somebody else's server passes through unchanged.** No code
|
|
48
|
+
* of ours runs there and nothing here can make its URL expire. That is the
|
|
49
|
+
* author's hosting decision, and the docs say so.
|
|
50
|
+
*
|
|
51
|
+
* ## A video with a copy at the delivery provider (AGL-2824)
|
|
52
|
+
*
|
|
53
|
+
* A caller that asks for it with `delivery` gets, for a video that passes
|
|
54
|
+
* rule 1, the delivery provider's own short-lived URL instead of the signed CDN
|
|
55
|
+
* URL, whenever `mediaDeliveryRedirect` finds a current copy and the release
|
|
56
|
+
* flag is on for the owning org. It is the URL the CDN would redirect the
|
|
57
|
+
* signed request to anyway, minted one hop earlier and bounded by the same
|
|
58
|
+
* lifetime. Anything else takes the signed CDN URL exactly as before.
|
|
59
|
+
*/
|
|
60
|
+
/** Why a stored URL was not turned into a link. */
|
|
61
|
+
export type PaidMediaRefusal =
|
|
62
|
+
/** A library asset the public can still fetch without a signature. */
|
|
63
|
+
'not-private'
|
|
64
|
+
/** No such asset, a deleted one, or one not shared with this site. */
|
|
65
|
+
| 'not-found'
|
|
66
|
+
/** Another site's library, another org's, or outside the media prefixes. */
|
|
67
|
+
| 'out-of-scope'
|
|
68
|
+
/** A Storage URL for a bucket this platform does not serve from. */
|
|
69
|
+
| 'foreign-storage'
|
|
70
|
+
/** Not a value any delivery can be built from. */
|
|
71
|
+
| 'malformed';
|
|
72
|
+
export type PaidMediaDelivery = {
|
|
73
|
+
ok: true;
|
|
74
|
+
via: 'signed-cdn';
|
|
75
|
+
location: string;
|
|
76
|
+
expiresAtMs: number;
|
|
77
|
+
/** The scope segment the signature covers. */
|
|
78
|
+
scope: string;
|
|
79
|
+
mediaId: string;
|
|
80
|
+
} | {
|
|
81
|
+
ok: true;
|
|
82
|
+
via: 'signed-storage';
|
|
83
|
+
location: string;
|
|
84
|
+
expiresAtMs: number;
|
|
85
|
+
objectPath: string;
|
|
86
|
+
} | {
|
|
87
|
+
ok: true;
|
|
88
|
+
via: 'external';
|
|
89
|
+
location: string;
|
|
90
|
+
} | {
|
|
91
|
+
ok: true;
|
|
92
|
+
via: 'delivery';
|
|
93
|
+
location: string;
|
|
94
|
+
expiresAtMs: number;
|
|
95
|
+
/** The scope segment the delivery was minted for. */
|
|
96
|
+
scope: string;
|
|
97
|
+
mediaId: string;
|
|
98
|
+
} | {
|
|
99
|
+
ok: false;
|
|
100
|
+
refusal: PaidMediaRefusal;
|
|
101
|
+
};
|
|
102
|
+
/** A document read, reduced to what this module asks of one. */
|
|
103
|
+
export interface PaidMediaDocument {
|
|
104
|
+
exists: boolean;
|
|
105
|
+
get(field: string): unknown;
|
|
106
|
+
}
|
|
107
|
+
/** Every read and signature this module needs, injectable for tests. */
|
|
108
|
+
export interface PaidMediaDeliveryIo {
|
|
109
|
+
/** The platform's media bucket; empty when unconfigured. */
|
|
110
|
+
bucketName: string;
|
|
111
|
+
readMedia(collection: 'hosts' | 'orgs', scopeId: string, mediaId: string): Promise<PaidMediaDocument>;
|
|
112
|
+
/** The org a site belongs to, or null for an unindexed site. */
|
|
113
|
+
orgIdForHost(hostId: string): Promise<string | null>;
|
|
114
|
+
/** A V4 signed read URL for one object in {@link bucketName}. */
|
|
115
|
+
signStorageRead(objectPath: string, expiresAtMs: number): Promise<string>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Resolves a stored product media URL to a redirect target that expires, or
|
|
119
|
+
* says why there is none. See the module comment for the rules.
|
|
120
|
+
*
|
|
121
|
+
* `cdnParams` ride on a signed CDN URL ahead of the signature, which covers
|
|
122
|
+
* `(scope, mediaId, exp)` and never the parameters, so they select a
|
|
123
|
+
* representation of the one asset the signature names and nothing else.
|
|
124
|
+
*/
|
|
125
|
+
export declare function resolvePaidMediaDelivery(options: {
|
|
126
|
+
stored: unknown;
|
|
127
|
+
/** The site selling the media; the only libraries it may sign from. */
|
|
128
|
+
hostId: string;
|
|
129
|
+
/** The lifetime of the link; bounded by `assertMediaSignatureTtl`. */
|
|
130
|
+
ttlMs: number;
|
|
131
|
+
cdnParams?: ReadonlyArray<readonly [string, string]>;
|
|
132
|
+
/**
|
|
133
|
+
* Hand a video with a current copy at the delivery provider its URL there
|
|
134
|
+
* (AGL-2824). `accept` is the request's `Accept`, which chooses the
|
|
135
|
+
* rendition when `cdnParams` asks for `?r=auto`. The provider and the flag
|
|
136
|
+
* verdict default to the registered provider and the release flag.
|
|
137
|
+
*/
|
|
138
|
+
delivery?: {
|
|
139
|
+
accept?: unknown;
|
|
140
|
+
provider?: MediaDeliveryProvider | null;
|
|
141
|
+
enabled?: (orgId: string | null) => Promise<boolean>;
|
|
142
|
+
};
|
|
143
|
+
nowMs?: number;
|
|
144
|
+
io: PaidMediaDeliveryIo;
|
|
145
|
+
}): Promise<PaidMediaDelivery>;
|
|
146
|
+
/**
|
|
147
|
+
* The production reads behind {@link resolvePaidMediaDelivery}, built on the
|
|
148
|
+
* caller's Firestore and bucket handles so a route's own mocks reach them.
|
|
149
|
+
*/
|
|
150
|
+
export declare function createPaidMediaDeliveryIo(options: {
|
|
151
|
+
firestore: {
|
|
152
|
+
collection(name: string): {
|
|
153
|
+
doc(id: string): {
|
|
154
|
+
get(): Promise<PaidMediaDocument>;
|
|
155
|
+
collection(name: string): {
|
|
156
|
+
doc(id: string): {
|
|
157
|
+
get(): Promise<PaidMediaDocument>;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
bucket: {
|
|
164
|
+
name?: string;
|
|
165
|
+
file(path: string): {
|
|
166
|
+
getSignedUrl(config: {
|
|
167
|
+
version: 'v4';
|
|
168
|
+
action: 'read';
|
|
169
|
+
expires: number;
|
|
170
|
+
}): Promise<[string] | string[]>;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
}): PaidMediaDeliveryIo;
|
|
@@ -0,0 +1,212 @@
|
|
|
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 { hostQualifiedScope, MEDIA_CDN_RENDITION_AUTO, MEDIA_CDN_RENDITION_PARAM, MEDIA_CDN_ROUTE, paidMediaAssetOfObject, parseMediaRenditions, parsePaidMediaSource } from "@aglyn/aglyn/server";
|
|
18
|
+
import { mediaDeliveryProvider } from "@aglyn/aglyn/plugin-manager/media-delivery-provider";
|
|
19
|
+
import { mediaDeliveryRedirect } from "@aglyn/tenant-data-admin/server/media-delivery";
|
|
20
|
+
import { assertMediaSignatureTtl, mediaSignatureQuery, mintMediaSignature } from "@aglyn/tenant-data-admin/server/media-signing";
|
|
21
|
+
import { isMediaStoragePathInScope } from "@aglyn/tenant-data-admin/server/media-storage-path";
|
|
22
|
+
import { mediaCdnScopeRefusal, parseMediaCdnScope, selectAutoRendition } from "@aglyn/tenant-data-admin/server/serve-media-cdn";
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a stored product media URL to a redirect target that expires, or
|
|
25
|
+
* says why there is none. See the module comment for the rules.
|
|
26
|
+
*
|
|
27
|
+
* `cdnParams` ride on a signed CDN URL ahead of the signature, which covers
|
|
28
|
+
* `(scope, mediaId, exp)` and never the parameters, so they select a
|
|
29
|
+
* representation of the one asset the signature names and nothing else.
|
|
30
|
+
*/ export async function resolvePaidMediaDelivery(options) {
|
|
31
|
+
var _options_nowMs;
|
|
32
|
+
const { hostId, ttlMs, io } = options;
|
|
33
|
+
const nowMs = (_options_nowMs = options.nowMs) != null ? _options_nowMs : Date.now();
|
|
34
|
+
const refuse = (refusal)=>({
|
|
35
|
+
ok: false,
|
|
36
|
+
refusal
|
|
37
|
+
});
|
|
38
|
+
if (!hostId) return refuse('out-of-scope');
|
|
39
|
+
// One lookup per call, and only for the forms that need to know the org.
|
|
40
|
+
let orgId;
|
|
41
|
+
const siteOrgId = ()=>orgId != null ? orgId : orgId = io.orgIdForHost(hostId);
|
|
42
|
+
/**
|
|
43
|
+
* The delivery provider's URL for a private library video, or null for
|
|
44
|
+
* the signed CDN URL. The representation is the one the CDN would pick for
|
|
45
|
+
* the same `?r=` and `Accept`, so the buyer gets the copy the signed URL
|
|
46
|
+
* would have been redirected to.
|
|
47
|
+
*/ const deliverFromProvider = async (delivery, asset)=>{
|
|
48
|
+
var _options_cdnParams;
|
|
49
|
+
var _find;
|
|
50
|
+
const provider = delivery.provider === undefined ? mediaDeliveryProvider('deliver') : delivery.provider;
|
|
51
|
+
if (!provider) return null;
|
|
52
|
+
const requested = (_find = ((_options_cdnParams = options.cdnParams) != null ? _options_cdnParams : []).find(([key])=>key === MEDIA_CDN_RENDITION_PARAM)) == null ? void 0 : _find[1];
|
|
53
|
+
const renditions = parseMediaRenditions(asset.document.get('videoRenditions'));
|
|
54
|
+
const rendition = !requested ? undefined : requested === MEDIA_CDN_RENDITION_AUTO ? selectAutoRendition(renditions, delivery.accept) : renditions.find((entry)=>entry.key === requested);
|
|
55
|
+
const redirect = await mediaDeliveryRedirect(_extends({
|
|
56
|
+
provider,
|
|
57
|
+
asset: {
|
|
58
|
+
collection: asset.collection,
|
|
59
|
+
scopeId: asset.scopeId,
|
|
60
|
+
mediaId: asset.mediaId
|
|
61
|
+
},
|
|
62
|
+
document: asset.document,
|
|
63
|
+
rendition,
|
|
64
|
+
servedType: rendition ? rendition.contentType : asset.document.get('contentType'),
|
|
65
|
+
claims: {
|
|
66
|
+
scope: asset.deliveryScope,
|
|
67
|
+
mediaId: asset.mediaId,
|
|
68
|
+
hostId
|
|
69
|
+
},
|
|
70
|
+
orgId: async ()=>asset.orgScope ? asset.scopeId : await siteOrgId()
|
|
71
|
+
}, delivery.enabled ? {
|
|
72
|
+
deliveryEnabled: delivery.enabled
|
|
73
|
+
} : {}, {
|
|
74
|
+
ttlMs,
|
|
75
|
+
nowMs
|
|
76
|
+
})).catch(()=>null);
|
|
77
|
+
if (!redirect) return null;
|
|
78
|
+
return {
|
|
79
|
+
ok: true,
|
|
80
|
+
via: 'delivery',
|
|
81
|
+
location: redirect.location,
|
|
82
|
+
expiresAtMs: redirect.expiresAtMs,
|
|
83
|
+
scope: asset.deliveryScope,
|
|
84
|
+
mediaId: asset.mediaId
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
const deliverAsset = async (scope, mediaId)=>{
|
|
88
|
+
var _options_cdnParams;
|
|
89
|
+
const parsed = parseMediaCdnScope(scope);
|
|
90
|
+
if (!parsed) return refuse('malformed');
|
|
91
|
+
let collection;
|
|
92
|
+
let deliveryScope;
|
|
93
|
+
if (parsed.isOrg) {
|
|
94
|
+
const owner = await siteOrgId();
|
|
95
|
+
if (!owner || parsed.scopeId !== owner) return refuse('out-of-scope');
|
|
96
|
+
collection = 'orgs';
|
|
97
|
+
deliveryScope = hostQualifiedScope(scope, hostId);
|
|
98
|
+
} else {
|
|
99
|
+
if (parsed.scopeId !== hostId) return refuse('out-of-scope');
|
|
100
|
+
collection = 'hosts';
|
|
101
|
+
deliveryScope = hostId;
|
|
102
|
+
}
|
|
103
|
+
const deliveryParsed = parseMediaCdnScope(deliveryScope);
|
|
104
|
+
if (!deliveryParsed) return refuse('malformed');
|
|
105
|
+
const document = await io.readMedia(collection, parsed.scopeId, mediaId);
|
|
106
|
+
if (!(document == null ? void 0 : document.exists) || document.get('deletedAt')) {
|
|
107
|
+
return refuse('not-found');
|
|
108
|
+
}
|
|
109
|
+
// The CDN would 404 an org asset this site is not allowed to use, so a
|
|
110
|
+
// link to one is a link that cannot play.
|
|
111
|
+
if (mediaCdnScopeRefusal(deliveryParsed, document.get('visibleTo'))) {
|
|
112
|
+
return refuse('not-found');
|
|
113
|
+
}
|
|
114
|
+
if (document.get('private') !== true) return refuse('not-private');
|
|
115
|
+
assertMediaSignatureTtl(ttlMs);
|
|
116
|
+
const delivered = options.delivery ? await deliverFromProvider(options.delivery, {
|
|
117
|
+
collection,
|
|
118
|
+
scopeId: parsed.scopeId,
|
|
119
|
+
orgScope: parsed.isOrg,
|
|
120
|
+
deliveryScope,
|
|
121
|
+
mediaId,
|
|
122
|
+
document
|
|
123
|
+
}) : null;
|
|
124
|
+
if (delivered) return delivered;
|
|
125
|
+
const signature = mintMediaSignature(deliveryScope, mediaId, nowMs, ttlMs);
|
|
126
|
+
const params = new URLSearchParams();
|
|
127
|
+
for (const [key, value] of (_options_cdnParams = options.cdnParams) != null ? _options_cdnParams : []){
|
|
128
|
+
if (key !== 'exp' && key !== 'sig') params.set(key, value);
|
|
129
|
+
}
|
|
130
|
+
const prefix = params.toString();
|
|
131
|
+
return {
|
|
132
|
+
ok: true,
|
|
133
|
+
via: 'signed-cdn',
|
|
134
|
+
location: `${MEDIA_CDN_ROUTE}/${deliveryScope}/${mediaId}?` + `${prefix ? `${prefix}&` : ''}${mediaSignatureQuery(signature)}`,
|
|
135
|
+
expiresAtMs: signature.exp,
|
|
136
|
+
scope: deliveryScope,
|
|
137
|
+
mediaId
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
const source = parsePaidMediaSource(options.stored);
|
|
141
|
+
switch(source.kind){
|
|
142
|
+
case 'malformed':
|
|
143
|
+
return refuse('malformed');
|
|
144
|
+
case 'external':
|
|
145
|
+
return {
|
|
146
|
+
ok: true,
|
|
147
|
+
via: 'external',
|
|
148
|
+
location: source.url
|
|
149
|
+
};
|
|
150
|
+
case 'asset':
|
|
151
|
+
return deliverAsset(source.scope, source.mediaId);
|
|
152
|
+
case 'storage-object':
|
|
153
|
+
{
|
|
154
|
+
if (!io.bucketName || source.bucket !== io.bucketName) {
|
|
155
|
+
return refuse('foreign-storage');
|
|
156
|
+
}
|
|
157
|
+
const { objectPath } = source;
|
|
158
|
+
const segments = objectPath.split('/');
|
|
159
|
+
let base = null;
|
|
160
|
+
if (segments[0] === 'hosts' && segments[1] === hostId) {
|
|
161
|
+
base = `hosts/${hostId}`;
|
|
162
|
+
} else if (segments[0] === 'orgs' && segments[1]) {
|
|
163
|
+
const owner = await siteOrgId();
|
|
164
|
+
if (owner && segments[1] === owner) base = `orgs/${owner}`;
|
|
165
|
+
}
|
|
166
|
+
// The same prefix test the CDN applies to a document's `storagePath`,
|
|
167
|
+
// which also refuses traversal and empty segments.
|
|
168
|
+
if (!base || !isMediaStoragePathInScope(objectPath, base)) {
|
|
169
|
+
return refuse('out-of-scope');
|
|
170
|
+
}
|
|
171
|
+
// An object keyed like an asset IS that asset, and the asset's own rules
|
|
172
|
+
// decide — including refusing it when the asset is still public.
|
|
173
|
+
const asset = paidMediaAssetOfObject(objectPath);
|
|
174
|
+
if (asset) return deliverAsset(asset.scope, asset.mediaId);
|
|
175
|
+
assertMediaSignatureTtl(ttlMs);
|
|
176
|
+
const expiresAtMs = nowMs + ttlMs;
|
|
177
|
+
return {
|
|
178
|
+
ok: true,
|
|
179
|
+
via: 'signed-storage',
|
|
180
|
+
location: await io.signStorageRead(objectPath, expiresAtMs),
|
|
181
|
+
expiresAtMs,
|
|
182
|
+
objectPath
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The production reads behind {@link resolvePaidMediaDelivery}, built on the
|
|
189
|
+
* caller's Firestore and bucket handles so a route's own mocks reach them.
|
|
190
|
+
*/ export function createPaidMediaDeliveryIo(options) {
|
|
191
|
+
var _ref;
|
|
192
|
+
const { firestore, bucket } = options;
|
|
193
|
+
return {
|
|
194
|
+
bucketName: String((_ref = bucket == null ? void 0 : bucket.name) != null ? _ref : ''),
|
|
195
|
+
readMedia: (collection, scopeId, mediaId)=>firestore.collection(collection).doc(scopeId).collection('media').doc(mediaId).get(),
|
|
196
|
+
orgIdForHost: async (hostId)=>{
|
|
197
|
+
const index = await firestore.collection('hostIndex').doc(hostId).get();
|
|
198
|
+
const orgId = index.exists ? index.get('orgId') : undefined;
|
|
199
|
+
return typeof orgId === 'string' && orgId ? orgId : null;
|
|
200
|
+
},
|
|
201
|
+
signStorageRead: async (objectPath, expiresAtMs)=>{
|
|
202
|
+
const [url] = await bucket.file(objectPath).getSignedUrl({
|
|
203
|
+
version: 'v4',
|
|
204
|
+
action: 'read',
|
|
205
|
+
expires: expiresAtMs
|
|
206
|
+
});
|
|
207
|
+
return String(url);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
//# sourceMappingURL=paid-media-delivery.js.map
|