@nextblock-cms/ecom 0.8.6 → 0.8.7
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/index.cjs.js +1 -1
- package/index.es.js +136 -533
- package/lib/CurrencyProvider.cjs.js +1 -0
- package/lib/CurrencyProvider.es.js +99 -0
- package/lib/cart-store.cjs.js +1 -0
- package/{cart-store.es.js → lib/cart-store.es.js} +13 -13
- package/lib/components/AccountNavigationMenu.cjs.js +1 -0
- package/lib/components/AccountNavigationMenu.es.js +44 -0
- package/lib/components/AddToCartButton.cjs.js +1 -0
- package/{AddToCartButton-ffE0DhHu.js → lib/components/AddToCartButton.es.js} +14 -13
- package/lib/components/Cart.cjs.js +1 -0
- package/lib/components/Cart.es.js +148 -0
- package/lib/components/CartDrawer.cjs.js +1 -0
- package/{components → lib/components}/CartDrawer.es.js +15 -14
- package/{components → lib/components}/CartIcon.cjs.js +1 -1
- package/{components → lib/components}/CartIcon.es.js +1 -0
- package/lib/components/Checkout.cjs.js +1 -0
- package/{components → lib/components}/Checkout.es.js +330 -363
- package/lib/components/CouponForm.cjs.js +1 -0
- package/lib/components/CouponForm.es.js +136 -0
- package/lib/components/CurrencySwitcher.cjs.js +1 -0
- package/{components → lib/components}/CurrencySwitcher.es.js +5 -4
- package/lib/components/CustomerProfileForm.cjs.js +1 -0
- package/lib/components/CustomerProfileForm.es.js +355 -0
- package/lib/components/FeaturedProduct.cjs.js +1 -0
- package/{components → lib/components}/FeaturedProduct.es.js +9 -8
- package/lib/components/InvoiceDocument.cjs.js +1 -0
- package/lib/components/InvoiceDocument.es.js +196 -0
- package/lib/components/InvoiceViewerShell.cjs.js +29 -0
- package/lib/components/InvoiceViewerShell.es.js +100 -0
- package/lib/components/ProductCard.cjs.js +1 -0
- package/lib/components/ProductCard.es.js +119 -0
- package/lib/components/ProductDetailsLayout.cjs.js +1 -0
- package/lib/components/ProductDetailsLayout.es.js +361 -0
- package/lib/components/ProductGallery.cjs.js +1 -0
- package/lib/components/ProductGallery.es.js +41 -0
- package/lib/components/ProductGrid.cjs.js +1 -0
- package/lib/components/ProductGrid.es.js +19 -0
- package/lib/components/ShippingEstimator.cjs.js +1 -0
- package/lib/components/ShippingEstimator.es.js +125 -0
- package/lib/components/SubscriptionSelector.cjs.js +1 -0
- package/lib/components/SubscriptionSelector.es.js +140 -0
- package/lib/countries.cjs.js +1 -0
- package/lib/countries.es.js +77 -0
- package/lib/coupon-server.cjs.js +1 -0
- package/{coupon-server-DUKVtyYs.js → lib/coupon-server.es.js} +68 -82
- package/lib/coupons.cjs.js +1 -0
- package/lib/coupons.es.js +17 -0
- package/lib/currency-store.cjs.js +1 -0
- package/lib/currency-store.es.js +27 -0
- package/lib/currency-sync.cjs.js +1 -0
- package/lib/currency-sync.es.js +180 -0
- package/lib/customer-addresses.cjs.js +1 -0
- package/lib/customer-addresses.es.js +116 -0
- package/lib/customer-orders.cjs.js +1 -0
- package/lib/customer-orders.es.js +45 -0
- package/lib/customer.cjs.js +1 -0
- package/{customer-C3xccjUg.js → lib/customer.es.js} +15 -14
- package/lib/export-helpers.cjs.js +1 -0
- package/lib/export-helpers.es.js +56 -0
- package/lib/factory.cjs.js +1 -0
- package/lib/factory.es.js +8 -0
- package/lib/freemius-coupons.cjs.js +1 -0
- package/lib/freemius-coupons.es.js +272 -0
- package/lib/freemius-order-sync.cjs.js +1 -0
- package/lib/freemius-order-sync.es.js +284 -0
- package/lib/inventory-settings.cjs.js +1 -0
- package/lib/inventory-settings.es.js +86 -0
- package/lib/invoice-server.cjs.js +33 -0
- package/lib/invoice-server.es.js +141 -0
- package/lib/invoice-ui.cjs.js +1 -0
- package/lib/invoice-ui.es.js +71 -0
- package/lib/invoice.cjs.js +1 -0
- package/lib/invoice.es.js +102 -0
- package/lib/order-inventory.cjs.js +61 -0
- package/lib/order-inventory.es.js +128 -0
- package/lib/order-tax-details.cjs.js +1 -0
- package/lib/order-tax-details.es.js +164 -0
- package/lib/pages/cms/coupons/CouponEditorForm.cjs.js +1 -0
- package/lib/pages/cms/coupons/CouponEditorForm.es.js +189 -0
- package/lib/pages/cms/coupons/CouponsPage.cjs.js +5 -0
- package/lib/pages/cms/coupons/CouponsPage.es.js +171 -0
- package/lib/pages/cms/coupons/CreateCouponDialog.cjs.js +1 -0
- package/lib/pages/cms/coupons/CreateCouponDialog.es.js +35 -0
- package/lib/pages/cms/coupons/EditCouponPage.cjs.js +1 -0
- package/lib/pages/cms/coupons/EditCouponPage.es.js +48 -0
- package/lib/pages/cms/coupons/ProductScopePicker.cjs.js +1 -0
- package/lib/pages/cms/coupons/ProductScopePicker.es.js +120 -0
- package/lib/pages/cms/coupons/actions.cjs.js +1 -0
- package/lib/pages/cms/coupons/actions.es.js +128 -0
- package/lib/pages/cms/coupons/product-options.cjs.js +1 -0
- package/lib/pages/cms/coupons/product-options.es.js +27 -0
- package/lib/pages/cms/orders/ExportReportsDialog.cjs.js +1 -0
- package/lib/pages/cms/orders/ExportReportsDialog.es.js +130 -0
- package/lib/pages/cms/orders/OrderDetailPage.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderDetailPage.es.js +137 -0
- package/lib/pages/cms/orders/OrderPrintButton.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderPrintButton.es.js +22 -0
- package/lib/pages/cms/orders/OrderStatusForm.cjs.js +1 -0
- package/lib/pages/cms/orders/OrderStatusForm.es.js +71 -0
- package/lib/pages/cms/orders/OrdersPage.cjs.js +1 -0
- package/lib/pages/cms/orders/OrdersPage.es.js +104 -0
- package/lib/pages/cms/orders/actions.cjs.js +7 -0
- package/lib/pages/cms/orders/actions.es.js +71 -0
- package/lib/pages/cms/orders/export-actions.cjs.js +1 -0
- package/lib/pages/cms/orders/export-actions.es.js +27 -0
- package/lib/pages/cms/orders/server-actions.cjs.js +1 -0
- package/lib/pages/cms/orders/server-actions.es.js +55 -0
- package/lib/pages/cms/payments/PaymentsClient.cjs.js +1 -0
- package/lib/pages/cms/payments/PaymentsClient.es.js +188 -0
- package/lib/pages/cms/payments/PaymentsPage.cjs.js +1 -0
- package/lib/pages/cms/payments/PaymentsPage.es.js +29 -0
- package/lib/pages/cms/payments/actions.cjs.js +1 -0
- package/lib/pages/cms/payments/actions.es.js +23 -0
- package/lib/pages/cms/payments/queries.cjs.js +1 -0
- package/lib/pages/cms/payments/queries.es.js +30 -0
- package/lib/pages/cms/products/ProductsPage.cjs.js +1 -0
- package/lib/pages/cms/products/ProductsPage.es.js +46 -0
- package/lib/pages/cms/products/_id_/edit/EditProductPage.cjs.js +1 -0
- package/lib/pages/cms/products/_id_/edit/EditProductPage.es.js +156 -0
- package/lib/pages/cms/products/actions.cjs.js +44 -0
- package/lib/pages/cms/products/actions.es.js +175 -0
- package/lib/pages/cms/products/attributes/AttributeManagementPage.cjs.js +1 -0
- package/lib/pages/cms/products/attributes/AttributeManagementPage.es.js +48 -0
- package/lib/pages/cms/products/attributes/components/AttributeManager.cjs.js +1 -0
- package/lib/pages/cms/products/attributes/components/AttributeManager.es.js +291 -0
- package/lib/pages/cms/products/categories/CategoryManagementPage.cjs.js +1 -0
- package/lib/pages/cms/products/categories/CategoryManagementPage.es.js +36 -0
- package/lib/pages/cms/products/categories/components/CategoryManager.cjs.js +1 -0
- package/lib/pages/cms/products/categories/components/CategoryManager.es.js +263 -0
- package/lib/pages/cms/products/components/CopyProductFromLanguage.cjs.js +1 -0
- package/lib/pages/cms/products/components/CopyProductFromLanguage.es.js +114 -0
- package/lib/pages/cms/products/components/CurrencyPriceFields.cjs.js +1 -0
- package/lib/pages/cms/products/components/CurrencyPriceFields.es.js +107 -0
- package/lib/pages/cms/products/components/DeleteProductButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/DeleteProductButton.es.js +48 -0
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.cjs.js +1 -0
- package/lib/pages/cms/products/components/FreemiusPricingDashboard.es.js +86 -0
- package/lib/pages/cms/products/components/ProductCategorySelector.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductCategorySelector.es.js +160 -0
- package/lib/pages/cms/products/components/ProductForm.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductForm.es.js +702 -0
- package/lib/pages/cms/products/components/ProductMediaManager.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductMediaManager.es.js +104 -0
- package/lib/pages/cms/products/components/ProductsBulkTable.cjs.js +1 -0
- package/lib/pages/cms/products/components/ProductsBulkTable.es.js +228 -0
- package/lib/pages/cms/products/components/SaleScheduleFields.cjs.js +1 -0
- package/lib/pages/cms/products/components/SaleScheduleFields.es.js +137 -0
- package/lib/pages/cms/products/components/SyncFreemiusButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/SyncFreemiusButton.es.js +36 -0
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.cjs.js +1 -0
- package/lib/pages/cms/products/components/SyncFreemiusPricingButton.es.js +40 -0
- package/lib/pages/cms/products/components/VariationsEditor.cjs.js +1 -0
- package/lib/pages/cms/products/components/VariationsEditor.es.js +408 -0
- package/lib/pages/cms/products/inventory/InventoryPage.cjs.js +1 -0
- package/lib/pages/cms/products/inventory/InventoryPage.es.js +16 -0
- package/lib/pages/cms/products/inventory/InventoryTableClient.cjs.js +2 -0
- package/lib/pages/cms/products/inventory/InventoryTableClient.es.js +214 -0
- package/lib/pages/cms/products/inventory/actions.cjs.js +3 -0
- package/lib/pages/cms/products/inventory/actions.es.js +95 -0
- package/lib/pages/cms/products/new/NewProductPage.cjs.js +1 -0
- package/lib/pages/cms/products/new/NewProductPage.es.js +76 -0
- package/lib/pages/cms/products/product-price-sync.cjs.js +1 -0
- package/lib/pages/cms/products/product-price-sync.es.js +98 -0
- package/lib/pages/cms/products/server-actions.cjs.js +1 -0
- package/lib/pages/cms/products/server-actions.es.js +193 -0
- package/lib/pages/cms/shipping/ShippingPage.cjs.js +5 -0
- package/lib/pages/cms/shipping/ShippingPage.es.js +211 -0
- package/lib/pages/cms/shipping/components/RateForm.cjs.js +1 -0
- package/lib/pages/cms/shipping/components/RateForm.es.js +441 -0
- package/lib/pages/cms/shipping/components/ZoneForm.cjs.js +1 -0
- package/lib/pages/cms/shipping/components/ZoneForm.es.js +228 -0
- package/lib/pages/cms/shipping/server-actions.cjs.js +1 -0
- package/lib/pages/cms/shipping/server-actions.es.js +159 -0
- package/lib/pages/cms/taxes/TaxesPage.cjs.js +1 -0
- package/lib/pages/cms/taxes/TaxesPage.es.js +172 -0
- package/lib/pages/cms/taxes/actions.cjs.js +1 -0
- package/lib/pages/cms/taxes/actions.es.js +57 -0
- package/lib/pages/cms/taxes/components/TaxRateForm.cjs.js +1 -0
- package/lib/pages/cms/taxes/components/TaxRateForm.es.js +100 -0
- package/lib/product-actions.cjs.js +237 -0
- package/lib/product-actions.es.js +524 -0
- package/lib/product-context.cjs.js +1 -0
- package/lib/product-context.es.js +16 -0
- package/lib/product-schema.cjs.js +1 -0
- package/lib/product-schema.es.js +134 -0
- package/lib/providers/freemius.cjs.js +5 -0
- package/lib/providers/freemius.es.js +538 -0
- package/lib/providers/stripe.cjs.js +1 -0
- package/lib/providers/stripe.es.js +473 -0
- package/lib/server-actions/coupon-actions.cjs.js +1 -0
- package/lib/server-actions/coupon-actions.es.js +23 -0
- package/lib/server-actions/customer-actions.cjs.js +1 -0
- package/lib/server-actions/customer-actions.es.js +30 -0
- package/lib/server-actions/product-actions.cjs.js +1 -0
- package/{server-actions → lib/server-actions}/product-actions.es.js +5 -4
- package/lib/server-actions/shipping-actions.cjs.js +1 -0
- package/{shipping-actions-BnHjlo2q.js → lib/server-actions/shipping-actions.es.js} +9 -7
- package/lib/server-actions/tax-actions.cjs.js +1 -0
- package/lib/server-actions/tax-actions.es.js +40 -0
- package/lib/shared-inventory.cjs.js +15 -0
- package/lib/shared-inventory.es.js +171 -0
- package/lib/shipping/resolver.cjs.js +7 -0
- package/lib/shipping/resolver.es.js +62 -0
- package/lib/shipping-rate-currency.cjs.js +1 -0
- package/lib/shipping-rate-currency.es.js +72 -0
- package/lib/states.cjs.js +1 -0
- package/{states-DlHJezQ1.js → lib/states.es.js} +27 -100
- package/lib/stripe/checkout.cjs.js +1 -0
- package/lib/stripe/checkout.es.js +182 -0
- package/lib/stripe/client.cjs.js +1 -0
- package/lib/stripe/client.es.js +7 -0
- package/lib/stripe/order-sync.cjs.js +1 -0
- package/lib/stripe/order-sync.es.js +130 -0
- package/lib/stripe/webhooks.cjs.js +1 -0
- package/lib/stripe/webhooks.es.js +30 -0
- package/lib/tax-calculation.cjs.js +1 -0
- package/lib/tax-calculation.es.js +101 -0
- package/lib/trials.cjs.js +1 -0
- package/{trials-RDcRAZKx.js → lib/trials.es.js} +9 -9
- package/{use-cart.es.js → lib/use-cart.es.js} +1 -0
- package/lib/zod-config.cjs.js +1 -0
- package/lib/zod-config.es.js +6 -0
- package/package.json +4 -4
- package/server.cjs.js +1 -110
- package/server.es.js +178 -6052
- package/AddToCartButton-DsSEH9yp.cjs +0 -1
- package/CouponForm-BI_5SBHQ.js +0 -152
- package/CouponForm-D_uu2bLP.cjs +0 -1
- package/CurrencyProvider-Cg-Q6ucj.cjs +0 -1
- package/CurrencyProvider-OzlRN96V.js +0 -120
- package/CurrencyProvider.cjs.js +0 -1
- package/CurrencyProvider.es.js +0 -10
- package/ProductDetailsLayout-BxJH_BxR.cjs +0 -1
- package/ProductDetailsLayout-Dg8dRTYp.js +0 -530
- package/ProductGrid-BdL7iglO.cjs +0 -1
- package/ProductGrid-D3AWM8sr.js +0 -130
- package/actions-AHmBrS5e.cjs +0 -48
- package/actions-j5fuSZX-.js +0 -820
- package/cart-store.cjs.js +0 -1
- package/components/Cart.cjs.js +0 -1
- package/components/Cart.es.js +0 -259
- package/components/CartDrawer.cjs.js +0 -1
- package/components/Checkout.cjs.js +0 -1
- package/components/CurrencySwitcher.cjs.js +0 -1
- package/components/FeaturedProduct.cjs.js +0 -1
- package/components/ProductDetailsLayout.cjs.js +0 -1
- package/components/ProductDetailsLayout.es.js +0 -19
- package/components/ProductGrid.cjs.js +0 -1
- package/components/ProductGrid.es.js +0 -6
- package/coupon-server-C9ySm3I5.cjs +0 -1
- package/customer-C-UPvrYN.cjs +0 -1
- package/invoice-ui-CAnJPu6n.cjs +0 -29
- package/invoice-ui-DtpbTJE1.js +0 -2886
- package/product-actions-CONBF8i6.cjs +0 -251
- package/product-actions-DjlIWCMH.js +0 -691
- package/resolver-Fz_FKsfX.cjs +0 -7
- package/resolver-cfrCaHpE.js +0 -128
- package/server-actions/product-actions.cjs.js +0 -1
- package/shipping-actions-D6zt20gg.cjs +0 -1
- package/states-CWYRxV4B.cjs +0 -1
- package/tax-calculation-Dab89aHd.js +0 -181
- package/tax-calculation-MkDKOEkL.cjs +0 -1
- package/trials-DvZaOtNy.cjs +0 -1
- /package/{components → lib/components}/SimpleTiptapRenderer.cjs.js +0 -0
- /package/{components → lib/components}/SimpleTiptapRenderer.es.js +0 -0
- /package/{currency-constants.cjs.js → lib/currency-constants.cjs.js} +0 -0
- /package/{currency-constants.es.js → lib/currency-constants.es.js} +0 -0
- /package/{currency-rest-client-uolJxUkL.cjs → lib/currency-rest-client.cjs.js} +0 -0
- /package/{currency-rest-client-CwoqdgAP.js → lib/currency-rest-client.es.js} +0 -0
- /package/{currency.cjs.js → lib/currency.cjs.js} +0 -0
- /package/{currency.es.js → lib/currency.es.js} +0 -0
- /package/{types.cjs.js → lib/types.cjs.js} +0 -0
- /package/{types.es.js → lib/types.es.js} +0 -0
- /package/{use-cart.cjs.js → lib/use-cart.cjs.js} +0 -0
- /package/{variation-utils.cjs.js → lib/variation-utils.cjs.js} +0 -0
- /package/{variation-utils.es.js → lib/variation-utils.es.js} +0 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const V=require("@supabase/supabase-js"),Z=require("crypto"),oe=require("@freemius/sdk"),ce=require("../customer.cjs.js"),Q=require("../coupon-server.cjs.js"),G=require("../customer-addresses.cjs.js"),j=require("../currency.cjs.js");function i(e){const r=process.env[e];if(!r)return null;const t=r.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).trim():t}function ae(e){const r=e?.trim();if(!r)return{firstName:null,lastName:null};const[t,...s]=r.split(/\s+/);return{firstName:t||null,lastName:s.length>0?s.join(" "):null}}function ee(e){if(e==null||e==="")return 0;const r=Number(e);return!Number.isFinite(r)||r<=0?0:Math.round(r)}function ue(e){return e===!0||e===1||e==="1"||e==="true"}function le(e,r){const t=e?.[r];return Array.isArray(t)?t:t&&typeof t=="object"?[t]:[]}function H(e,r){for(const t of r){const s=le(e,t);if(s.length>0)return s}return Array.isArray(e)?e:[]}function A(e){if(e==null||e==="")return null;const r=Number(e);return Number.isFinite(r)?r:null}function de(e){return e===null?0:e>5e3?(console.warn(`[Freemius Sync] Suspiciously high price detected: ${e}. Assuming it is already in cents.`),Math.round(e)):Math.round(e*100)}function pe(e){const r=Number(e);return!Number.isFinite(r)||r<1?1:Math.round(r)}function re(){const e=i("FREEMIUS_CHECKOUT_PRODUCTS_JSON");if(!e)return null;try{const r=JSON.parse(e);return r&&typeof r=="object"?r:null}catch(r){return console.error("[Freemius Checkout] Failed to parse FREEMIUS_CHECKOUT_PRODUCTS_JSON:",r),null}}function te(e){const r=re(),t=String(e),s=r?.[t],c=i("FREEMIUS_PRODUCT_ID"),d=i("FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY"),f=i("FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY");return s?.publicKey?{publicKey:s.publicKey,secretKey:s.secretKey??null,apiKey:s.apiKey??null,source:"product-map"}:process.env.FREEMIUS_SANDBOX_ENABLED==="true"&&c&&c===t&&d?{publicKey:d,secretKey:f,apiKey:i("FREEMIUS_API_KEY"),source:"single-product-sandbox-env"}:c&&c===t&&i("FREEMIUS_PUBLIC_KEY")?{publicKey:i("FREEMIUS_PUBLIC_KEY"),secretKey:i("FREEMIUS_SECRET_KEY"),apiKey:i("FREEMIUS_API_KEY"),source:"single-product-env"}:{publicKey:i("FREEMIUS_PUBLIC_KEY"),secretKey:i("FREEMIUS_SECRET_KEY"),apiKey:i("FREEMIUS_API_KEY"),source:"legacy-env"}}async function _e(e){if(!e.apiKey)throw new Error("Missing Freemius API key for SDK sandbox generation.");return new oe.Freemius({productId:Number(e.productId),apiKey:e.apiKey,secretKey:e.secretKey,publicKey:e.publicKey}).checkout.getSandboxParams()}class me{getProviderName(){return"Freemius"}async createCheckoutSession({items:r,customerEmail:t,customerPhone:s,userId:c,billingAddress:d,shippingAddress:f,currencyCode:m,couponCode:b,couponContextItems:g}){const a=process.env.NEXT_PUBLIC_SUPABASE_URL,u=process.env.SUPABASE_SERVICE_ROLE_KEY;if(!a||!u)return{error:"Missing Supabase credentials for checkout (Service Key required).",url:null};const p=V.createClient(a,u);if(!r||r.length===0)return{error:"Cart is empty",url:null};if(r.length!==1)return{error:"Freemius items must be checked out one at a time.",url:null};const{data:E,error:w}=await p.from("currencies").select("code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount").eq("is_active",!0).order("code",{ascending:!0}),v=E??[];if(w||v.length===0)return{error:"Failed to resolve store currencies",url:null};const X=j.getDefaultCurrency(v),K=v.find(l=>l.code===(m||"").toUpperCase())??X,y=r[0],{data:o,error:M}=await p.from("products").select("id, title, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, freemius_plan_id, freemius_product_id, trial_period_days, trial_requires_payment_method").eq("id",y.product_id).single();if(M||!o)return{error:"Product not found",url:null};const U=o.freemius_plan_id,F=o.freemius_product_id;if(!U||!F)return{error:"Product is not configured for Freemius checkout (missing Plan ID or Product ID)",url:null};const D=j.resolveEffectivePriceForCurrency({prices:o.prices||{},salePrices:o.sale_prices||{},fallbackPrice:o.price,fallbackSalePrice:o.sale_price,saleStartAt:o.sale_start_at,saleEndAt:o.sale_end_at,scheduledPrice:o.scheduled_price,scheduledPrices:o.scheduled_prices||{},scheduledPriceAt:o.scheduled_price_at,currencyCode:K.code,currencies:v}),q=D.sale_price??D.price,N=j.isSaleWindowActive({saleStartAt:o.sale_start_at,saleEndAt:o.sale_end_at}),S=q*y.quantity;let n=null,_=0;if(b){const l=await Q.getCouponQuote({client:p,code:b,items:g&&g.length>0?g:r,currencyCode:K.code});if(!l.success)return{error:l.error,errorKey:l.errorKey,errorStatus:400,url:null};n=l.quote,_=Math.min(S,n.lineDiscounts.filter($=>$.product_id===o.id).reduce(($,L)=>$+L.discount,0))}const P=ee(o.trial_period_days),R=P>0?y.trial_preference?y.trial_preference:o.trial_requires_payment_method?"paid":"free":null,O="pending",h=ae(d?.recipient_name??null),{data:Y,error:J}=await p.from("orders").insert({status:O,total:Math.max(0,S-_),currency:K.code,exchange_rate_at_purchase:K.exchange_rate,subtotal:S,discount_total:_,coupon_id:n?.couponId??null,coupon_code:n?.code??null,discount_details:n?{code:n.code,discount_type:n.discountType,discount_amount:n.discountAmount,provider:"freemius",provider_discounts:n.providerDiscounts,line_discounts:n.lineDiscounts,final_amount_owned_by:"freemius"}:null,provider:"freemius",freemius_product_id:String(F),freemius_plan_id:String(U),user_id:c||null,customer_details:ce.normalizeOrderCustomerDetails({email:t,phone:s,name:d?.recipient_name,billing:d,shipping:f})}).select("id").single();if(J||!Y)return console.error("Failed to create pending order:",J),{error:"Failed to initiate order",url:null};const{error:W}=await p.from("order_items").insert([{order_id:Y.id,product_id:o.id,quantity:y.quantity,price_at_purchase:q}]);if(W&&console.error("Failed to insert order items:",W),c)try{await G.upsertDefaultUserAddresses({userId:c,billingAddress:d,shippingAddress:f,client:p}),await G.fillMissingUserProfileCheckoutDetails({userId:c,fullName:d?.recipient_name??f?.recipient_name??null,phone:s,client:p})}catch(l){console.error("Failed to sync checkout profile defaults before checkout:",l)}n&&await Q.recordCouponRedemption({client:p,quote:n,orderId:Y.id,provider:"freemius",discountTotal:_,userId:c,customerEmail:t,metadata:{currency:K.code,subtotal:S,final_amount_owned_by:"freemius"}});const x=process.env.FREEMIUS_SANDBOX_ENABLED==="true",I=te(F),k=I.publicKey,T=I.secretKey,z=I.apiKey;if(!k||x&&!T)return{error:"Missing FREEMIUS credentials (PUBLIC_KEY or SECRET_KEY) in environment variables.",url:null};if(x&&I.source==="legacy-env"){const l=i("FREEMIUS_PRODUCT_ID"),$=!!i("FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY"),L=!!i("FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY");console.warn(`[Freemius Checkout] Sandbox is enabled for product ${F}, but no product-scoped checkout credentials were selected. Falling back to legacy FREEMIUS_PUBLIC_KEY/FREEMIUS_SECRET_KEY may open live checkout instead of sandbox.`,{configuredProductId:l,productIdsMatch:l===String(F),hasSandboxOverridePublicKey:$,hasSandboxOverrideSecretKey:L,hasCheckoutProductsJson:!!i("FREEMIUS_CHECKOUT_PRODUCTS_JSON")})}let B=!1;if(x&&T&&k)try{B=await _e({productId:F,publicKey:k,secretKey:T,apiKey:z})}catch(l){console.warn("Freemius Checkout - SDK sandbox generation failed. Falling back to manual token generation.",l,{credentialSource:I.source,hasApiKey:!!z});const $=Math.floor(Date.now()/1e3).toString(),L=`${$}${F}${T}${k}checkout`,ie=Z.createHash("md5").update(L).digest("hex");B={ctx:$,token:ie}}const C=new URL(`https://checkout.freemius.com/app/${F}/plan/${U}/`);if(x&&T&&k?(C.searchParams.append("sandbox",B.token),C.searchParams.append("s_ctx_ts",B.ctx)):x&&C.searchParams.append("sandbox","true"),t&&C.searchParams.append("user_email",t),h.firstName&&C.searchParams.append("user_firstname",h.firstName),h.lastName&&C.searchParams.append("user_lastname",h.lastName),C.searchParams.append("currency",K.code.toLowerCase()),y.billing_cycle&&C.searchParams.append("billing_cycle",y.billing_cycle),R&&C.searchParams.append("trial",R),n)C.searchParams.append("coupon",n.code);else if(N){const{data:l}=await p.from("product_freemius_sale_coupons").select("freemius_coupon_code, is_active, starts_at, ends_at, sync_status").eq("product_id",o.id).maybeSingle();l?.is_active&&l.sync_status==="synced"&&l.freemius_coupon_code&&j.isSaleWindowActive({saleStartAt:l.starts_at,saleEndAt:l.ends_at})&&C.searchParams.append("coupon",l.freemius_coupon_code)}return{url:C.toString(),customProps:{provider:"freemius",plugin_id:F,plan_id:U,public_key:k,user_email:t,user_firstname:h.firstName,user_lastname:h.lastName,credential_source:I.source,sandbox:B,billing_cycle:y.billing_cycle,trial:R,trial_period_days:P,trial_requires_payment_method:o.trial_requires_payment_method,initial_order_status:O,coupon:n?.code??null,order_id:Y.id}}}}async function ne(e,r,t,s){const d=new Date().toUTCString().replace("GMT","+0000"),f=`GET
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
${d}
|
|
5
|
+
${e}`,m=Z.createHmac("sha256",s).update(f).digest("hex"),b=Buffer.from(m).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,""),g=`FS ${r}:${t}:${b}`,a=await fetch(`https://api.freemius.com${e}`,{headers:{Authorization:g,Date:d,Accept:"application/json"}});if(!a.ok){const u=await a.text();throw console.error(`[Freemius API] [ERROR] ${e} returned ${a.status}: ${u}`),new Error(`Freemius API failed on ${e}: ${a.status} - ${u}`)}return a.json()}async function fe(){const e=i("FREEMIUS_DEVELOPER_ID"),r=i("FREEMIUS_PUBLIC_KEY"),t=i("FREEMIUS_SECRET_KEY"),s=process.env.NEXT_PUBLIC_SUPABASE_URL,c=process.env.SUPABASE_SERVICE_ROLE_KEY;if(!e||!r||!t||!s||!c)throw new Error("Missing necessary environment variables for Freemius Sync.");const d=V.createClient(s,c,{auth:{autoRefreshToken:!1,persistSession:!1}}),f=m=>ne(m,e,r,t);try{console.log(`[Freemius Sync] Fetching all plugins for developer ${e}...`);const m=await f(`/v1/developers/${e}/plugins.json`),b=H(m,["plugins","plugin"]);console.log(`[Freemius Sync] Found ${b.length} plugins. Syncing plans...`);let g=0;const{data:a}=await d.from("languages").select("id").eq("code","en").single(),u=a?.id;if(!u)throw new Error("English language not found in database. Cannot sync products.");for(const p of b){const E=p.id?.toString();if(!E){console.warn("[Freemius Sync] Skipping plugin without an id:",p);continue}const w=await se(d,e,E,p.title||p.name||`Freemius Product ${E}`,f,u);g+=w}return{success:!0,count:g}}catch(m){throw console.error("[Freemius Sync] Global Error:",m),m}}async function ge(e){const r=i("FREEMIUS_DEVELOPER_ID"),t=i("FREEMIUS_PUBLIC_KEY"),s=i("FREEMIUS_SECRET_KEY"),c=process.env.NEXT_PUBLIC_SUPABASE_URL,d=process.env.SUPABASE_SERVICE_ROLE_KEY;if(!r||!t||!s||!c||!d)throw new Error("Missing environment variables for Freemius Sync.");const f=V.createClient(c,d),m=E=>ne(E,r,t,s),{data:b}=await f.from("languages").select("id").eq("code","en").single(),g=b?.id;if(!g)throw new Error("English language not found in database. Cannot sync products.");const a=await m(`/v1/developers/${r}/plugins/${e}.json`),u=a.plugin??a;return{success:!0,count:await se(f,r,e,u.title||u.name||`Freemius Product ${e}`,m,g)}}async function se(e,r,t,s,c,d){console.log(`[Freemius Sync] Fetching plans for plugin: ${s} (${t})...`);let f=0;try{const m=`/v1/developers/${r}/plugins/${t}/plans.json`,b=await c(m),g=H(b,["plans","plan"]);console.log(`[Freemius Sync] Received ${g.length} plans for plugin ${t}.`);for(const a of g){const u=a.id?.toString();if(!u){console.warn("[Freemius Sync] Skipping plan without an id:",a);continue}const p=a.name||a.title||u,E=a.title||p;console.log(`[Freemius Sync] Processing plan: ${E} (${u})...`);let w=a;if(w.trial_period===void 0||w.is_require_subscription===void 0)try{const n=`/v1/developers/${r}/plugins/${t}/plans/${u}.json`,_=await c(n),P=_.plan??_;w={...w,...P}}catch(n){console.warn(`[Freemius Sync] Could not fetch trial details for plan ${u}:`,n instanceof Error?n.message:n)}const v=ee(w.trial_period),X=v>0&&ue(w.is_require_subscription);let K=0,y=[];try{const n=`/v1/developers/${r}/plugins/${t}/plans/${u}/pricing.json`,_=await c(n);if(y=H(_,["pricing","prices","pricings"]),y.length>0){const P=y[0],R=A(P.annual_price)??A(P.monthly_price)??A(P.lifetime_price);K=de(R)}console.log(`[Freemius Sync] Plan: ${E} -> Resolved Price (cents): ${K}`)}catch(n){console.warn(`[Freemius Sync] Could not fetch pricing for plan ${u}:`,n instanceof Error?n.message:n)}const o=`${s}-${E}`.toLowerCase().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/^-+|-+$/g,""),M={title:`${s} - ${E}`,slug:o,short_description:a.description||"",price:K,product_type:"digital",payment_provider:"freemius",freemius_plan_id:u,freemius_product_id:t,trial_period_days:v,trial_requires_payment_method:X,status:"active",stock:999,sku:`FM-${t}-${u}`,language_id:d},{data:U,error:F}=await e.from("products").upsert(M,{onConflict:"language_id, sku"}).select();if(F||!U||U.length===0){console.error(`[Freemius Sync] Error upserting product ${M.sku}:`,F);continue}const D=U[0].id,{data:q,error:N}=await e.from("freemius_plans").select("id").eq("product_id",D).eq("name",p).maybeSingle();N&&console.warn(`[Freemius Sync] Could not check existing local plan for ${M.sku}:`,N.message||N);let S="";if(q){S=q.id;const{error:n}=await e.from("freemius_plans").update({title:E,updated_at:new Date().toISOString()}).eq("id",S);n&&console.warn(`[Freemius Sync] Could not update local plan ${S}:`,n.message||n)}else{const{data:n,error:_}=await e.from("freemius_plans").insert({product_id:D,name:p,title:E}).select("id").single();_&&console.warn(`[Freemius Sync] Could not insert local plan for ${M.sku}:`,_.message||_),n&&(S=n.id)}if(S&&y.length>0)for(const n of y){const _=pe(n.licenses??n.license_quota??n.quota),{data:P,error:R}=await e.from("freemius_pricing").select("id").eq("plan_id",S).eq("license_quota",_).maybeSingle();R&&console.warn(`[Freemius Sync] Could not check pricing for plan ${S}, quota ${_}:`,R.message||R);const O={api_monthly_price:A(n.monthly_price),api_annual_price:A(n.annual_price),api_lifetime_price:A(n.lifetime_price),updated_at:new Date().toISOString()};if(P){const{error:h}=await e.from("freemius_pricing").update(O).eq("id",P.id);h&&console.warn(`[Freemius Sync] Could not update pricing ${P.id}:`,h.message||h)}else{const{error:h}=await e.from("freemius_pricing").insert({plan_id:S,license_quota:_,...O});h&&console.warn(`[Freemius Sync] Could not insert pricing for plan ${S}, quota ${_}:`,h.message||h)}}console.log(`[Freemius Sync] Successfully fully synced product ${M.sku}.`),f++}}catch(m){console.error(`[Freemius Sync] Failed sync for plugin ${t}:`,m.message)}return f}exports.FreemiusProvider=me;exports.parseFreemiusCheckoutCredentialsMap=re;exports.readFreemiusEnvValue=i;exports.resolveFreemiusCheckoutCredentials=te;exports.syncFreemiusProductsToSupabase=fe;exports.syncSingleFreemiusProduct=ge;
|
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
import { createClient as H } from "@supabase/supabase-js";
|
|
2
|
+
import Q from "crypto";
|
|
3
|
+
import { Freemius as te } from "@freemius/sdk";
|
|
4
|
+
import { normalizeOrderCustomerDetails as ne } from "../customer.es.js";
|
|
5
|
+
import { getCouponQuote as ie, recordCouponRedemption as se } from "../coupon-server.es.js";
|
|
6
|
+
import { upsertDefaultUserAddresses as oe, fillMissingUserProfileCheckoutDetails as ae } from "../customer-addresses.es.js";
|
|
7
|
+
import { getDefaultCurrency as ce, resolveEffectivePriceForCurrency as le, isSaleWindowActive as z } from "../currency.es.js";
|
|
8
|
+
function o(e) {
|
|
9
|
+
const r = process.env[e];
|
|
10
|
+
if (!r)
|
|
11
|
+
return null;
|
|
12
|
+
const t = r.trim();
|
|
13
|
+
return t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'") ? t.slice(1, -1).trim() : t;
|
|
14
|
+
}
|
|
15
|
+
function ue(e) {
|
|
16
|
+
const r = e?.trim();
|
|
17
|
+
if (!r)
|
|
18
|
+
return {
|
|
19
|
+
firstName: null,
|
|
20
|
+
lastName: null
|
|
21
|
+
};
|
|
22
|
+
const [t, ...i] = r.split(/\s+/);
|
|
23
|
+
return {
|
|
24
|
+
firstName: t || null,
|
|
25
|
+
lastName: i.length > 0 ? i.join(" ") : null
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function G(e) {
|
|
29
|
+
if (e == null || e === "")
|
|
30
|
+
return 0;
|
|
31
|
+
const r = Number(e);
|
|
32
|
+
return !Number.isFinite(r) || r <= 0 ? 0 : Math.round(r);
|
|
33
|
+
}
|
|
34
|
+
function de(e) {
|
|
35
|
+
return e === !0 || e === 1 || e === "1" || e === "true";
|
|
36
|
+
}
|
|
37
|
+
function pe(e, r) {
|
|
38
|
+
const t = e?.[r];
|
|
39
|
+
return Array.isArray(t) ? t : t && typeof t == "object" ? [t] : [];
|
|
40
|
+
}
|
|
41
|
+
function X(e, r) {
|
|
42
|
+
for (const t of r) {
|
|
43
|
+
const i = pe(e, t);
|
|
44
|
+
if (i.length > 0)
|
|
45
|
+
return i;
|
|
46
|
+
}
|
|
47
|
+
return Array.isArray(e) ? e : [];
|
|
48
|
+
}
|
|
49
|
+
function k(e) {
|
|
50
|
+
if (e == null || e === "")
|
|
51
|
+
return null;
|
|
52
|
+
const r = Number(e);
|
|
53
|
+
return Number.isFinite(r) ? r : null;
|
|
54
|
+
}
|
|
55
|
+
function _e(e) {
|
|
56
|
+
return e === null ? 0 : e > 5e3 ? (console.warn(
|
|
57
|
+
`[Freemius Sync] Suspiciously high price detected: ${e}. Assuming it is already in cents.`
|
|
58
|
+
), Math.round(e)) : Math.round(e * 100);
|
|
59
|
+
}
|
|
60
|
+
function me(e) {
|
|
61
|
+
const r = Number(e);
|
|
62
|
+
return !Number.isFinite(r) || r < 1 ? 1 : Math.round(r);
|
|
63
|
+
}
|
|
64
|
+
function fe() {
|
|
65
|
+
const e = o("FREEMIUS_CHECKOUT_PRODUCTS_JSON");
|
|
66
|
+
if (!e)
|
|
67
|
+
return null;
|
|
68
|
+
try {
|
|
69
|
+
const r = JSON.parse(e);
|
|
70
|
+
return r && typeof r == "object" ? r : null;
|
|
71
|
+
} catch (r) {
|
|
72
|
+
return console.error(
|
|
73
|
+
"[Freemius Checkout] Failed to parse FREEMIUS_CHECKOUT_PRODUCTS_JSON:",
|
|
74
|
+
r
|
|
75
|
+
), null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function ge(e) {
|
|
79
|
+
const r = fe(), t = String(e), i = r?.[t], a = o("FREEMIUS_PRODUCT_ID"), d = o(
|
|
80
|
+
"FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY"
|
|
81
|
+
), f = o(
|
|
82
|
+
"FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY"
|
|
83
|
+
);
|
|
84
|
+
return i?.publicKey ? {
|
|
85
|
+
publicKey: i.publicKey,
|
|
86
|
+
secretKey: i.secretKey ?? null,
|
|
87
|
+
apiKey: i.apiKey ?? null,
|
|
88
|
+
source: "product-map"
|
|
89
|
+
} : process.env.FREEMIUS_SANDBOX_ENABLED === "true" && a && a === t && d ? {
|
|
90
|
+
publicKey: d,
|
|
91
|
+
secretKey: f,
|
|
92
|
+
apiKey: o("FREEMIUS_API_KEY"),
|
|
93
|
+
source: "single-product-sandbox-env"
|
|
94
|
+
} : a && a === t && o("FREEMIUS_PUBLIC_KEY") ? {
|
|
95
|
+
publicKey: o("FREEMIUS_PUBLIC_KEY"),
|
|
96
|
+
secretKey: o("FREEMIUS_SECRET_KEY"),
|
|
97
|
+
apiKey: o("FREEMIUS_API_KEY"),
|
|
98
|
+
source: "single-product-env"
|
|
99
|
+
} : {
|
|
100
|
+
publicKey: o("FREEMIUS_PUBLIC_KEY"),
|
|
101
|
+
secretKey: o("FREEMIUS_SECRET_KEY"),
|
|
102
|
+
apiKey: o("FREEMIUS_API_KEY"),
|
|
103
|
+
source: "legacy-env"
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function Ee(e) {
|
|
107
|
+
if (!e.apiKey)
|
|
108
|
+
throw new Error("Missing Freemius API key for SDK sandbox generation.");
|
|
109
|
+
return new te({
|
|
110
|
+
productId: Number(e.productId),
|
|
111
|
+
apiKey: e.apiKey,
|
|
112
|
+
secretKey: e.secretKey,
|
|
113
|
+
publicKey: e.publicKey
|
|
114
|
+
}).checkout.getSandboxParams();
|
|
115
|
+
}
|
|
116
|
+
class we {
|
|
117
|
+
getProviderName() {
|
|
118
|
+
return "Freemius";
|
|
119
|
+
}
|
|
120
|
+
async createCheckoutSession({
|
|
121
|
+
items: r,
|
|
122
|
+
customerEmail: t,
|
|
123
|
+
customerPhone: i,
|
|
124
|
+
userId: a,
|
|
125
|
+
billingAddress: d,
|
|
126
|
+
shippingAddress: f,
|
|
127
|
+
currencyCode: m,
|
|
128
|
+
couponCode: b,
|
|
129
|
+
couponContextItems: g
|
|
130
|
+
}) {
|
|
131
|
+
const c = process.env.NEXT_PUBLIC_SUPABASE_URL, l = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
132
|
+
if (!c || !l)
|
|
133
|
+
return { error: "Missing Supabase credentials for checkout (Service Key required).", url: null };
|
|
134
|
+
const p = H(c, l);
|
|
135
|
+
if (!r || r.length === 0)
|
|
136
|
+
return { error: "Cart is empty", url: null };
|
|
137
|
+
if (r.length !== 1)
|
|
138
|
+
return { error: "Freemius items must be checked out one at a time.", url: null };
|
|
139
|
+
const { data: E, error: w } = await p.from("currencies").select(
|
|
140
|
+
"code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount"
|
|
141
|
+
).eq("is_active", !0).order("code", { ascending: !0 }), I = E ?? [];
|
|
142
|
+
if (w || I.length === 0)
|
|
143
|
+
return { error: "Failed to resolve store currencies", url: null };
|
|
144
|
+
const j = ce(I), K = I.find((u) => u.code === (m || "").toUpperCase()) ?? j, y = r[0], { data: s, error: M } = await p.from("products").select("id, title, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, freemius_plan_id, freemius_product_id, trial_period_days, trial_requires_payment_method").eq("id", y.product_id).single();
|
|
145
|
+
if (M || !s)
|
|
146
|
+
return { error: "Product not found", url: null };
|
|
147
|
+
const U = s.freemius_plan_id, F = s.freemius_product_id;
|
|
148
|
+
if (!U || !F)
|
|
149
|
+
return { error: "Product is not configured for Freemius checkout (missing Plan ID or Product ID)", url: null };
|
|
150
|
+
const A = le({
|
|
151
|
+
prices: s.prices || {},
|
|
152
|
+
salePrices: s.sale_prices || {},
|
|
153
|
+
fallbackPrice: s.price,
|
|
154
|
+
fallbackSalePrice: s.sale_price,
|
|
155
|
+
saleStartAt: s.sale_start_at,
|
|
156
|
+
saleEndAt: s.sale_end_at,
|
|
157
|
+
scheduledPrice: s.scheduled_price,
|
|
158
|
+
scheduledPrices: s.scheduled_prices || {},
|
|
159
|
+
scheduledPriceAt: s.scheduled_price_at,
|
|
160
|
+
currencyCode: K.code,
|
|
161
|
+
currencies: I
|
|
162
|
+
}), N = A.sale_price ?? A.price, x = z({
|
|
163
|
+
saleStartAt: s.sale_start_at,
|
|
164
|
+
saleEndAt: s.sale_end_at
|
|
165
|
+
}), S = N * y.quantity;
|
|
166
|
+
let n = null, _ = 0;
|
|
167
|
+
if (b) {
|
|
168
|
+
const u = await ie({
|
|
169
|
+
client: p,
|
|
170
|
+
code: b,
|
|
171
|
+
items: g && g.length > 0 ? g : r,
|
|
172
|
+
currencyCode: K.code
|
|
173
|
+
});
|
|
174
|
+
if (!u.success)
|
|
175
|
+
return {
|
|
176
|
+
error: u.error,
|
|
177
|
+
errorKey: u.errorKey,
|
|
178
|
+
errorStatus: 400,
|
|
179
|
+
url: null
|
|
180
|
+
};
|
|
181
|
+
n = u.quote, _ = Math.min(
|
|
182
|
+
S,
|
|
183
|
+
n.lineDiscounts.filter(($) => $.product_id === s.id).reduce(($, T) => $ + T.discount, 0)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
const P = G(s.trial_period_days), R = P > 0 ? y.trial_preference ? y.trial_preference : s.trial_requires_payment_method ? "paid" : "free" : null, O = "pending", h = ue(
|
|
187
|
+
d?.recipient_name ?? null
|
|
188
|
+
), { data: Y, error: V } = await p.from("orders").insert({
|
|
189
|
+
status: O,
|
|
190
|
+
total: Math.max(0, S - _),
|
|
191
|
+
currency: K.code,
|
|
192
|
+
exchange_rate_at_purchase: K.exchange_rate,
|
|
193
|
+
subtotal: S,
|
|
194
|
+
discount_total: _,
|
|
195
|
+
coupon_id: n?.couponId ?? null,
|
|
196
|
+
coupon_code: n?.code ?? null,
|
|
197
|
+
discount_details: n ? {
|
|
198
|
+
code: n.code,
|
|
199
|
+
discount_type: n.discountType,
|
|
200
|
+
discount_amount: n.discountAmount,
|
|
201
|
+
provider: "freemius",
|
|
202
|
+
provider_discounts: n.providerDiscounts,
|
|
203
|
+
line_discounts: n.lineDiscounts,
|
|
204
|
+
final_amount_owned_by: "freemius"
|
|
205
|
+
} : null,
|
|
206
|
+
provider: "freemius",
|
|
207
|
+
freemius_product_id: String(F),
|
|
208
|
+
freemius_plan_id: String(U),
|
|
209
|
+
user_id: a || null,
|
|
210
|
+
customer_details: ne({
|
|
211
|
+
email: t,
|
|
212
|
+
phone: i,
|
|
213
|
+
name: d?.recipient_name,
|
|
214
|
+
billing: d,
|
|
215
|
+
shipping: f
|
|
216
|
+
})
|
|
217
|
+
}).select("id").single();
|
|
218
|
+
if (V || !Y)
|
|
219
|
+
return console.error("Failed to create pending order:", V), { error: "Failed to initiate order", url: null };
|
|
220
|
+
const { error: J } = await p.from("order_items").insert([{
|
|
221
|
+
order_id: Y.id,
|
|
222
|
+
product_id: s.id,
|
|
223
|
+
quantity: y.quantity,
|
|
224
|
+
price_at_purchase: N
|
|
225
|
+
}]);
|
|
226
|
+
if (J && console.error("Failed to insert order items:", J), a)
|
|
227
|
+
try {
|
|
228
|
+
await oe({
|
|
229
|
+
userId: a,
|
|
230
|
+
billingAddress: d,
|
|
231
|
+
shippingAddress: f,
|
|
232
|
+
client: p
|
|
233
|
+
}), await ae({
|
|
234
|
+
userId: a,
|
|
235
|
+
fullName: d?.recipient_name ?? f?.recipient_name ?? null,
|
|
236
|
+
phone: i,
|
|
237
|
+
client: p
|
|
238
|
+
});
|
|
239
|
+
} catch (u) {
|
|
240
|
+
console.error(
|
|
241
|
+
"Failed to sync checkout profile defaults before checkout:",
|
|
242
|
+
u
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
n && await se({
|
|
246
|
+
client: p,
|
|
247
|
+
quote: n,
|
|
248
|
+
orderId: Y.id,
|
|
249
|
+
provider: "freemius",
|
|
250
|
+
discountTotal: _,
|
|
251
|
+
userId: a,
|
|
252
|
+
customerEmail: t,
|
|
253
|
+
metadata: {
|
|
254
|
+
currency: K.code,
|
|
255
|
+
subtotal: S,
|
|
256
|
+
final_amount_owned_by: "freemius"
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
const q = process.env.FREEMIUS_SANDBOX_ENABLED === "true", v = ge(F), D = v.publicKey, B = v.secretKey, W = v.apiKey;
|
|
260
|
+
if (!D || q && !B)
|
|
261
|
+
return { error: "Missing FREEMIUS credentials (PUBLIC_KEY or SECRET_KEY) in environment variables.", url: null };
|
|
262
|
+
if (q && v.source === "legacy-env") {
|
|
263
|
+
const u = o("FREEMIUS_PRODUCT_ID"), $ = !!o("FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY"), T = !!o("FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY");
|
|
264
|
+
console.warn(
|
|
265
|
+
`[Freemius Checkout] Sandbox is enabled for product ${F}, but no product-scoped checkout credentials were selected. Falling back to legacy FREEMIUS_PUBLIC_KEY/FREEMIUS_SECRET_KEY may open live checkout instead of sandbox.`,
|
|
266
|
+
{
|
|
267
|
+
configuredProductId: u,
|
|
268
|
+
productIdsMatch: u === String(F),
|
|
269
|
+
hasSandboxOverridePublicKey: $,
|
|
270
|
+
hasSandboxOverrideSecretKey: T,
|
|
271
|
+
hasCheckoutProductsJson: !!o("FREEMIUS_CHECKOUT_PRODUCTS_JSON")
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
let L = !1;
|
|
276
|
+
if (q && B && D)
|
|
277
|
+
try {
|
|
278
|
+
L = await Ee({
|
|
279
|
+
productId: F,
|
|
280
|
+
publicKey: D,
|
|
281
|
+
secretKey: B,
|
|
282
|
+
apiKey: W
|
|
283
|
+
});
|
|
284
|
+
} catch (u) {
|
|
285
|
+
console.warn(
|
|
286
|
+
"Freemius Checkout - SDK sandbox generation failed. Falling back to manual token generation.",
|
|
287
|
+
u,
|
|
288
|
+
{
|
|
289
|
+
credentialSource: v.source,
|
|
290
|
+
hasApiKey: !!W
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
const $ = Math.floor(Date.now() / 1e3).toString(), T = `${$}${F}${B}${D}checkout`, re = Q.createHash("md5").update(T).digest("hex");
|
|
294
|
+
L = {
|
|
295
|
+
ctx: $,
|
|
296
|
+
token: re
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const C = new URL(`https://checkout.freemius.com/app/${F}/plan/${U}/`);
|
|
300
|
+
if (q && B && D ? (C.searchParams.append("sandbox", L.token), C.searchParams.append("s_ctx_ts", L.ctx)) : q && C.searchParams.append("sandbox", "true"), t && C.searchParams.append("user_email", t), h.firstName && C.searchParams.append("user_firstname", h.firstName), h.lastName && C.searchParams.append("user_lastname", h.lastName), C.searchParams.append("currency", K.code.toLowerCase()), y.billing_cycle && C.searchParams.append("billing_cycle", y.billing_cycle), R && C.searchParams.append("trial", R), n)
|
|
301
|
+
C.searchParams.append("coupon", n.code);
|
|
302
|
+
else if (x) {
|
|
303
|
+
const { data: u } = await p.from("product_freemius_sale_coupons").select("freemius_coupon_code, is_active, starts_at, ends_at, sync_status").eq("product_id", s.id).maybeSingle();
|
|
304
|
+
u?.is_active && u.sync_status === "synced" && u.freemius_coupon_code && z({
|
|
305
|
+
saleStartAt: u.starts_at,
|
|
306
|
+
saleEndAt: u.ends_at
|
|
307
|
+
}) && C.searchParams.append("coupon", u.freemius_coupon_code);
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
url: C.toString(),
|
|
311
|
+
customProps: {
|
|
312
|
+
provider: "freemius",
|
|
313
|
+
plugin_id: F,
|
|
314
|
+
plan_id: U,
|
|
315
|
+
public_key: D,
|
|
316
|
+
user_email: t,
|
|
317
|
+
user_firstname: h.firstName,
|
|
318
|
+
user_lastname: h.lastName,
|
|
319
|
+
credential_source: v.source,
|
|
320
|
+
sandbox: L,
|
|
321
|
+
billing_cycle: y.billing_cycle,
|
|
322
|
+
trial: R,
|
|
323
|
+
trial_period_days: P,
|
|
324
|
+
trial_requires_payment_method: s.trial_requires_payment_method,
|
|
325
|
+
initial_order_status: O,
|
|
326
|
+
coupon: n?.code ?? null,
|
|
327
|
+
order_id: Y.id
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async function Z(e, r, t, i) {
|
|
333
|
+
const d = (/* @__PURE__ */ new Date()).toUTCString().replace("GMT", "+0000"), f = `GET
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
${d}
|
|
337
|
+
${e}`, m = Q.createHmac("sha256", i).update(f).digest("hex"), b = Buffer.from(m).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""), g = `FS ${r}:${t}:${b}`, c = await fetch(`https://api.freemius.com${e}`, {
|
|
338
|
+
headers: {
|
|
339
|
+
Authorization: g,
|
|
340
|
+
Date: d,
|
|
341
|
+
Accept: "application/json"
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
if (!c.ok) {
|
|
345
|
+
const l = await c.text();
|
|
346
|
+
throw console.error(`[Freemius API] [ERROR] ${e} returned ${c.status}: ${l}`), new Error(`Freemius API failed on ${e}: ${c.status} - ${l}`);
|
|
347
|
+
}
|
|
348
|
+
return c.json();
|
|
349
|
+
}
|
|
350
|
+
async function Ke() {
|
|
351
|
+
const e = o("FREEMIUS_DEVELOPER_ID"), r = o("FREEMIUS_PUBLIC_KEY"), t = o("FREEMIUS_SECRET_KEY"), i = process.env.NEXT_PUBLIC_SUPABASE_URL, a = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
352
|
+
if (!e || !r || !t || !i || !a)
|
|
353
|
+
throw new Error("Missing necessary environment variables for Freemius Sync.");
|
|
354
|
+
const d = H(i, a, {
|
|
355
|
+
auth: { autoRefreshToken: !1, persistSession: !1 }
|
|
356
|
+
}), f = (m) => Z(m, e, r, t);
|
|
357
|
+
try {
|
|
358
|
+
console.log(`[Freemius Sync] Fetching all plugins for developer ${e}...`);
|
|
359
|
+
const m = await f(`/v1/developers/${e}/plugins.json`), b = X(m, ["plugins", "plugin"]);
|
|
360
|
+
console.log(`[Freemius Sync] Found ${b.length} plugins. Syncing plans...`);
|
|
361
|
+
let g = 0;
|
|
362
|
+
const { data: c } = await d.from("languages").select("id").eq("code", "en").single(), l = c?.id;
|
|
363
|
+
if (!l)
|
|
364
|
+
throw new Error("English language not found in database. Cannot sync products.");
|
|
365
|
+
for (const p of b) {
|
|
366
|
+
const E = p.id?.toString();
|
|
367
|
+
if (!E) {
|
|
368
|
+
console.warn("[Freemius Sync] Skipping plugin without an id:", p);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const w = await ee(
|
|
372
|
+
d,
|
|
373
|
+
e,
|
|
374
|
+
E,
|
|
375
|
+
p.title || p.name || `Freemius Product ${E}`,
|
|
376
|
+
f,
|
|
377
|
+
l
|
|
378
|
+
);
|
|
379
|
+
g += w;
|
|
380
|
+
}
|
|
381
|
+
return { success: !0, count: g };
|
|
382
|
+
} catch (m) {
|
|
383
|
+
throw console.error("[Freemius Sync] Global Error:", m), m;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async function Re(e) {
|
|
387
|
+
const r = o("FREEMIUS_DEVELOPER_ID"), t = o("FREEMIUS_PUBLIC_KEY"), i = o("FREEMIUS_SECRET_KEY"), a = process.env.NEXT_PUBLIC_SUPABASE_URL, d = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
388
|
+
if (!r || !t || !i || !a || !d)
|
|
389
|
+
throw new Error("Missing environment variables for Freemius Sync.");
|
|
390
|
+
const f = H(a, d), m = (E) => Z(E, r, t, i), { data: b } = await f.from("languages").select("id").eq("code", "en").single(), g = b?.id;
|
|
391
|
+
if (!g)
|
|
392
|
+
throw new Error("English language not found in database. Cannot sync products.");
|
|
393
|
+
const c = await m(`/v1/developers/${r}/plugins/${e}.json`), l = c.plugin ?? c;
|
|
394
|
+
return { success: !0, count: await ee(
|
|
395
|
+
f,
|
|
396
|
+
r,
|
|
397
|
+
e,
|
|
398
|
+
l.title || l.name || `Freemius Product ${e}`,
|
|
399
|
+
m,
|
|
400
|
+
g
|
|
401
|
+
) };
|
|
402
|
+
}
|
|
403
|
+
async function ee(e, r, t, i, a, d) {
|
|
404
|
+
console.log(`[Freemius Sync] Fetching plans for plugin: ${i} (${t})...`);
|
|
405
|
+
let f = 0;
|
|
406
|
+
try {
|
|
407
|
+
const m = `/v1/developers/${r}/plugins/${t}/plans.json`, b = await a(m), g = X(b, ["plans", "plan"]);
|
|
408
|
+
console.log(`[Freemius Sync] Received ${g.length} plans for plugin ${t}.`);
|
|
409
|
+
for (const c of g) {
|
|
410
|
+
const l = c.id?.toString();
|
|
411
|
+
if (!l) {
|
|
412
|
+
console.warn("[Freemius Sync] Skipping plan without an id:", c);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const p = c.name || c.title || l, E = c.title || p;
|
|
416
|
+
console.log(`[Freemius Sync] Processing plan: ${E} (${l})...`);
|
|
417
|
+
let w = c;
|
|
418
|
+
if (w.trial_period === void 0 || w.is_require_subscription === void 0)
|
|
419
|
+
try {
|
|
420
|
+
const n = `/v1/developers/${r}/plugins/${t}/plans/${l}.json`, _ = await a(n), P = _.plan ?? _;
|
|
421
|
+
w = {
|
|
422
|
+
...w,
|
|
423
|
+
...P
|
|
424
|
+
};
|
|
425
|
+
} catch (n) {
|
|
426
|
+
console.warn(
|
|
427
|
+
`[Freemius Sync] Could not fetch trial details for plan ${l}:`,
|
|
428
|
+
n instanceof Error ? n.message : n
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
const I = G(w.trial_period), j = I > 0 && de(w.is_require_subscription);
|
|
432
|
+
let K = 0, y = [];
|
|
433
|
+
try {
|
|
434
|
+
const n = `/v1/developers/${r}/plugins/${t}/plans/${l}/pricing.json`, _ = await a(n);
|
|
435
|
+
if (y = X(_, [
|
|
436
|
+
"pricing",
|
|
437
|
+
"prices",
|
|
438
|
+
"pricings"
|
|
439
|
+
]), y.length > 0) {
|
|
440
|
+
const P = y[0], R = k(P.annual_price) ?? k(P.monthly_price) ?? k(P.lifetime_price);
|
|
441
|
+
K = _e(R);
|
|
442
|
+
}
|
|
443
|
+
console.log(`[Freemius Sync] Plan: ${E} -> Resolved Price (cents): ${K}`);
|
|
444
|
+
} catch (n) {
|
|
445
|
+
console.warn(`[Freemius Sync] Could not fetch pricing for plan ${l}:`, n instanceof Error ? n.message : n);
|
|
446
|
+
}
|
|
447
|
+
const s = `${i}-${E}`.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/^-+|-+$/g, ""), M = {
|
|
448
|
+
title: `${i} - ${E}`,
|
|
449
|
+
slug: s,
|
|
450
|
+
short_description: c.description || "",
|
|
451
|
+
price: K,
|
|
452
|
+
product_type: "digital",
|
|
453
|
+
payment_provider: "freemius",
|
|
454
|
+
freemius_plan_id: l,
|
|
455
|
+
freemius_product_id: t,
|
|
456
|
+
trial_period_days: I,
|
|
457
|
+
trial_requires_payment_method: j,
|
|
458
|
+
status: "active",
|
|
459
|
+
stock: 999,
|
|
460
|
+
sku: `FM-${t}-${l}`,
|
|
461
|
+
language_id: d
|
|
462
|
+
}, { data: U, error: F } = await e.from("products").upsert(M, { onConflict: "language_id, sku" }).select();
|
|
463
|
+
if (F || !U || U.length === 0) {
|
|
464
|
+
console.error(`[Freemius Sync] Error upserting product ${M.sku}:`, F);
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
const A = U[0].id, { data: N, error: x } = await e.from("freemius_plans").select("id").eq("product_id", A).eq("name", p).maybeSingle();
|
|
468
|
+
x && console.warn(
|
|
469
|
+
`[Freemius Sync] Could not check existing local plan for ${M.sku}:`,
|
|
470
|
+
x.message || x
|
|
471
|
+
);
|
|
472
|
+
let S = "";
|
|
473
|
+
if (N) {
|
|
474
|
+
S = N.id;
|
|
475
|
+
const { error: n } = await e.from("freemius_plans").update({ title: E, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", S);
|
|
476
|
+
n && console.warn(
|
|
477
|
+
`[Freemius Sync] Could not update local plan ${S}:`,
|
|
478
|
+
n.message || n
|
|
479
|
+
);
|
|
480
|
+
} else {
|
|
481
|
+
const { data: n, error: _ } = await e.from("freemius_plans").insert({
|
|
482
|
+
product_id: A,
|
|
483
|
+
name: p,
|
|
484
|
+
title: E
|
|
485
|
+
}).select("id").single();
|
|
486
|
+
_ && console.warn(
|
|
487
|
+
`[Freemius Sync] Could not insert local plan for ${M.sku}:`,
|
|
488
|
+
_.message || _
|
|
489
|
+
), n && (S = n.id);
|
|
490
|
+
}
|
|
491
|
+
if (S && y.length > 0)
|
|
492
|
+
for (const n of y) {
|
|
493
|
+
const _ = me(
|
|
494
|
+
n.licenses ?? n.license_quota ?? n.quota
|
|
495
|
+
), { data: P, error: R } = await e.from("freemius_pricing").select("id").eq("plan_id", S).eq("license_quota", _).maybeSingle();
|
|
496
|
+
R && console.warn(
|
|
497
|
+
`[Freemius Sync] Could not check pricing for plan ${S}, quota ${_}:`,
|
|
498
|
+
R.message || R
|
|
499
|
+
);
|
|
500
|
+
const O = {
|
|
501
|
+
api_monthly_price: k(n.monthly_price),
|
|
502
|
+
api_annual_price: k(n.annual_price),
|
|
503
|
+
api_lifetime_price: k(n.lifetime_price),
|
|
504
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
505
|
+
};
|
|
506
|
+
if (P) {
|
|
507
|
+
const { error: h } = await e.from("freemius_pricing").update(O).eq("id", P.id);
|
|
508
|
+
h && console.warn(
|
|
509
|
+
`[Freemius Sync] Could not update pricing ${P.id}:`,
|
|
510
|
+
h.message || h
|
|
511
|
+
);
|
|
512
|
+
} else {
|
|
513
|
+
const { error: h } = await e.from("freemius_pricing").insert({
|
|
514
|
+
plan_id: S,
|
|
515
|
+
license_quota: _,
|
|
516
|
+
...O
|
|
517
|
+
});
|
|
518
|
+
h && console.warn(
|
|
519
|
+
`[Freemius Sync] Could not insert pricing for plan ${S}, quota ${_}:`,
|
|
520
|
+
h.message || h
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
console.log(`[Freemius Sync] Successfully fully synced product ${M.sku}.`), f++;
|
|
525
|
+
}
|
|
526
|
+
} catch (m) {
|
|
527
|
+
console.error(`[Freemius Sync] Failed sync for plugin ${t}:`, m.message);
|
|
528
|
+
}
|
|
529
|
+
return f;
|
|
530
|
+
}
|
|
531
|
+
export {
|
|
532
|
+
we as FreemiusProvider,
|
|
533
|
+
fe as parseFreemiusCheckoutCredentialsMap,
|
|
534
|
+
o as readFreemiusEnvValue,
|
|
535
|
+
ge as resolveFreemiusCheckoutCredentials,
|
|
536
|
+
Ke as syncFreemiusProductsToSupabase,
|
|
537
|
+
Re as syncSingleFreemiusProduct
|
|
538
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const U=require("../stripe/client.cjs.js"),ke=require("@supabase/supabase-js"),Ee=require("../countries.cjs.js"),Pe=require("../customer.cjs.js"),R=require("../coupon-server.cjs.js"),be=require("../coupons.cjs.js"),_e=require("../customer-addresses.cjs.js"),T=require("../inventory-settings.cjs.js"),w=require("../tax-calculation.cjs.js"),h=require("../currency.cjs.js"),Te=require("../order-tax-details.cjs.js"),we=require("../types.cjs.js"),Ie=require("../variation-utils.cjs.js"),Ae=Ee.countries.map(r=>r.code),De=new Set(["bg","cs","da","de","el","en","en-GB","es","es-419","et","fi","fil","fr","hr","hu","id","it","ja","ko","lt","lv","ms","mt","nb","nl","pl","pt","pt-BR","ro","ru","sk","sl","sv","th","tr","vi","zh","zh-HK","zh-TW"]);function pe(r){if(r)return{line1:r.line1||void 0,line2:r.line2||void 0,city:r.city||void 0,state:r.state||void 0,postal_code:r.postal_code||void 0,country:r.country_code||void 0}}function Me(r){const i=r?.trim().replace("_","-");if(!i)return;const l=[i,i.toLowerCase(),i.split("-")[0].toLowerCase()];for(const d of l)if(De.has(d))return d}function Ue(r,i){return Ie.resolveTranslatedText(r.name,r.name_translations||null,i)}async function Le(r){if(!r.email)return null;const i=pe(r.shippingAddress),l=r.shippingAddress?.recipient_name||r.billingAddress?.recipient_name||void 0,d={email:r.email,name:r.billingAddress?.recipient_name||r.shippingAddress?.recipient_name||void 0,phone:r.phone||void 0,address:pe(r.billingAddress),metadata:r.userId?{userId:r.userId}:void 0,...i&&l?{shipping:{name:l,phone:r.phone||void 0,address:i}}:{}};try{const s=(await U.stripe.customers.list({email:r.email,limit:1})).data[0];return s?(await U.stripe.customers.update(s.id,d),s.id):(await U.stripe.customers.create(d)).id}catch(_){return console.error("Failed to upsert Stripe customer for checkout prefill:",_),null}}class Fe{getProviderName(){return"Stripe"}async createCheckoutSession({items:i,customerEmail:l,customerPhone:d,userId:_,billingAddress:s,shippingAddress:y,shippingMethodId:z,currencyCode:me,locale:B,couponCode:K,couponContextItems:L}){const Q=process.env.NEXT_PUBLIC_SUPABASE_URL,$=process.env.SUPABASE_SERVICE_ROLE_KEY;if(!Q||!$)return console.error("Missing Supabase credentials for checkout (Service Key required)."),{error:"Internal Server Error",url:null};const a=ke.createClient(Q,$),X=process.env.NEXT_PUBLIC_URL||"http://localhost:4200",H=i.some(e=>!we.isDigitalItem(e));if(!i.length)return{error:"Cart is empty",url:null};const{data:he,error:j}=await a.from("currencies").select("code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount").eq("is_active",!0).order("code",{ascending:!0}),g=he??[];if(j||g.length===0)return console.error("Error fetching currencies for checkout:",j),{error:"Failed to resolve store currencies",url:null};const G=h.getDefaultCurrency(g),p=g.find(e=>e.code===(me||"").toUpperCase())??G,F=p.code.toLowerCase(),V=await T.getEcommerceInventorySettings(a),ve=i.map(e=>e.product_id),W=i.map(e=>e.variant_id).filter(e=>!!e),{data:J,error:Y}=await a.from("products").select("id, title, sku, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, stock, is_taxable").in("id",ve);if(Y||!J)return console.error("Error fetching products for validation:",Y),{error:"Failed to validate product prices",url:null};const{data:fe,error:Z}=W.length?await a.from("product_variants").select("id, product_id, sku, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, stock_quantity").in("id",W):{data:[],error:null};if(Z)return console.error("Error fetching variants for validation:",Z),{error:"Failed to validate product variants",url:null};const ee=new Map(J.map(e=>[e.id,e])),te=new Map((fe||[]).map(e=>[e.id,e])),N=new Set,I=new Map;for(const e of i){const t=ee.get(e.product_id);if(!t)continue;const n=(e.variant_id?te.get(e.variant_id):null)?.sku||t.sku;n&&(N.add(n),I.set(n,(I.get(n)??0)+e.quantity))}const{data:ye,error:re}=N.size?await a.from("inventory_items").select("sku, quantity").in("sku",[...N]):{data:[],error:null};if(re)return console.error("Error fetching SKU inventory for validation:",re),{error:"Failed to validate SKU inventory",url:null};const A=new Map((ye||[]).map(e=>[e.sku,Math.max(0,e.quantity??0)])),S=[],oe=[],ie=[];let v=0,C=0,c=null;if(K){const e=await R.getCouponQuote({client:a,code:K,items:L&&L.length>0?L:i,currencyCode:p.code});if(!e.success)return{error:e.error,errorKey:e.errorKey,errorStatus:400,url:null};c=e.quote}const ge=R.getQuoteLineDiscountMap(c),Se=e=>{const t=e.unitAmount*e.quantity,f=Math.max(0,t-e.lineDiscount);if(f<=0)return;const n=Math.floor(f/e.quantity),P=f-n*e.quantity,k=(b,E)=>{E<=0||b<=0||S.push({price_data:{currency:e.currency,product_data:{name:e.name,tax_code:w.getStripeTaxCodeForProduct(e.isTaxable),metadata:{productId:e.productId,variantId:e.variantId||""}},tax_behavior:"exclusive",unit_amount:b},quantity:E})};k(n,e.quantity-P),k(n+1,P)};for(const e of i){const t=ee.get(e.product_id);if(!t)return console.warn(`Product ${e.product_id} not found in DB.`),{url:null,...T.createInventoryUnavailableError(e.title)};const f=h.resolveEffectivePriceForCurrency({prices:h.normalizePriceMap(t.prices),salePrices:t.sale_prices||{},fallbackPrice:t.price,fallbackSalePrice:t.sale_price,saleStartAt:t.sale_start_at,saleEndAt:t.sale_end_at,scheduledPrice:t.scheduled_price,scheduledPrices:h.normalizePriceMap(t.scheduled_prices),scheduledPriceAt:t.scheduled_price_at,currencyCode:p.code,currencies:g});let n=f.sale_price??f.price,P=t.title,k=null;if(e.variant_id){const o=te.get(e.variant_id);if(!o||o.product_id!==e.product_id)return{url:null,...T.createInventoryUnavailableError(e.title)};const M=I.get(o.sku)??e.quantity,le=A.has(o.sku)?A.get(o.sku)??0:Math.max(0,o.stock_quantity??0);if(V.trackQuantities&&M>le)return{url:null,...T.createInventoryInsufficientError(e.title,le)};const de=h.resolveEffectivePriceForCurrency({prices:h.normalizePriceMap(o.prices),salePrices:o.sale_prices||{},fallbackPrice:o.price,fallbackSalePrice:o.sale_price,saleStartAt:o.sale_start_at,saleEndAt:o.sale_end_at,scheduledPrice:o.scheduled_price,scheduledPrices:h.normalizePriceMap(o.scheduled_prices),scheduledPriceAt:o.scheduled_price_at,currencyCode:p.code,currencies:g});n=de.sale_price??de.price,k=o.id,P=e.variant_label?`${t.title} - ${e.variant_label}`:`${t.title} - ${o.sku}`}else{const o=I.get(t.sku)??e.quantity,M=A.has(t.sku)?A.get(t.sku)??0:Math.max(0,t.stock??0);if(V.trackQuantities&&o>M)return{url:null,...T.createInventoryInsufficientError(e.title,M)}}const b=t.is_taxable??!0;if(n<0)return{error:"A product variation produced an invalid price.",url:null};const E=Math.min(n*e.quantity,ge.get(be.getCartLineCouponKey(e))??0);Se({name:P,currency:F,productId:t.id,variantId:k,isTaxable:b,unitAmount:n,quantity:e.quantity,lineDiscount:E}),v+=n*e.quantity,C+=E,ie.push({product_id:t.id,quantity:e.quantity,price_at_purchase:n,variant_id:k}),oe.push({product_id:t.id,quantity:e.quantity,unit_amount:n,discount_amount:E,is_taxable:b})}if(S.length===0&&C>=v)return{error:"This coupon would reduce the Stripe order to zero. Use a smaller discount for Stripe checkout.",errorKey:"ecommerce.coupon_zero_total_not_supported",errorStatus:400,url:null};if(S.length===0)return{error:"No valid items in cart",url:null};let m=0,O=null;if(z){const{data:e,error:t}=await a.from("shipping_zone_methods").select("id, name, name_translations, cost_amount, cost_currency").eq("id",z).single();if(t)return console.error("Failed to load shipping method:",t),{error:"Failed to load shipping method",url:null};m=h.convertMinorUnitAmount({amount:e.cost_amount??0,fromCurrencyCode:e.cost_currency||G.code,toCurrencyCode:p.code,currencies:g}),O=Ue(e,B)}const ae=H?y??s:s;let u;try{u=await w.calculateCheckoutTaxes(a,{items:oe,destination:{country_code:ae?.country_code,state:ae?.state}})}catch(e){return console.error("Failed to calculate checkout taxes:",e),{error:"Failed to calculate taxes",url:null}}m>0&&O&&S.push({price_data:{currency:F,product_data:{name:O,tax_code:u.enabled&&u.mode==="automatic"?w.STRIPE_TAX_CODE_SHIPPING:w.STRIPE_TAX_CODE_NONTAXABLE},tax_behavior:"exclusive",unit_amount:m},quantity:1});const q=u.enabled&&u.mode==="manual"&&!u.isPendingExternalCalculation?u.amount:0;q>0&&S.push({price_data:{currency:F,product_data:{name:"Tax",tax_code:w.STRIPE_TAX_CODE_NONTAXABLE},tax_behavior:"exclusive",unit_amount:q},quantity:1});const Ce=Pe.normalizeOrderCustomerDetails({email:l,phone:d,name:s?.recipient_name,billing:s,shipping:y}),ne=p.code,qe=Te.buildOrderTaxDetailsFromCalculation({calculation:u,subtotal:v,shippingTotal:m,total:Math.max(0,v-C)+m+q,currency:ne}),xe=Math.max(0,v-C)+m+q,{data:ce,error:se}=await a.from("orders").insert({status:"pending",total:xe,currency:ne,exchange_rate_at_purchase:p.exchange_rate,subtotal:v,shipping_total:m,tax_total:q,tax_details:qe,coupon_id:c?.couponId??null,coupon_code:c?.code??null,discount_total:C,discount_details:c?{code:c.code,discount_type:c.discountType,discount_amount:c.discountAmount,provider:"stripe",provider_discounts:c.providerDiscounts,line_discounts:c.lineDiscounts}:null,provider:"stripe",user_id:_,customer_details:Ce}).select("id").single();if(se||!ce)return console.error("Failed to create pending order:",se),{error:"Failed to initiate order",url:null};const x=ce.id,{error:ue}=await a.from("order_items").insert(ie.map(e=>({order_id:x,product_id:e.product_id,variant_id:e.variant_id??null,quantity:e.quantity,price_at_purchase:e.price_at_purchase})));if(ue)return console.error("Failed to insert order items:",ue),await a.from("orders").update({status:"failed"}).eq("id",x),{error:"Failed to record order items",url:null};if(_)try{await _e.upsertDefaultUserAddresses({userId:_,billingAddress:s,shippingAddress:y,client:a}),await _e.fillMissingUserProfileCheckoutDetails({userId:_,fullName:s?.recipient_name??y?.recipient_name??null,phone:d,client:a})}catch(e){console.error("Failed to sync checkout profile defaults before checkout:",e)}c&&await R.recordCouponRedemption({client:a,quote:c,orderId:x,provider:"stripe",discountTotal:C,userId:_,customerEmail:l,metadata:{currency:p.code,subtotal:v,shipping_total:m,tax_total:q}});const D=await Le({email:l,phone:d,userId:_,billingAddress:s,shippingAddress:y});try{const e=await U.stripe.checkout.sessions.create({mode:"payment",success_url:`${X}/checkout/success?session_id={CHECKOUT_SESSION_ID}`,cancel_url:`${X}/checkout`,locale:Me(B),line_items:S,automatic_tax:u.enabled&&u.mode==="automatic"?{enabled:!0}:void 0,billing_address_collection:"auto",customer:D||void 0,customer_email:D?void 0:l||void 0,customer_creation:D?void 0:"if_required",customer_update:D?{name:"auto",address:"auto",shipping:"auto"}:void 0,shipping_address_collection:H?{allowed_countries:Ae}:void 0,metadata:{orderId:x,taxMode:u.mode,currencyCode:p.code,couponCode:c?.code||""}}),{error:t}=await a.from("orders").update({stripe_session_id:e.id}).eq("id",x);return t&&console.error("Failed to save Stripe session ID on order:",t),{url:e.url}}catch(e){return console.error("Stripe session creation failed:",e),await a.from("orders").update({status:"failed"}).eq("id",x),{error:e.message,url:null}}}}exports.StripeProvider=Fe;
|