@nextblock-cms/ecom 0.22.1 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +43 -43
  2. package/index.cjs +1 -1
  3. package/index.es.js +31 -31
  4. package/lib/components/Checkout.cjs +1 -1
  5. package/lib/components/Checkout.es.js +1 -0
  6. package/lib/components/SubscriptionSelector.cjs +1 -1
  7. package/lib/components/SubscriptionSelector.es.js +91 -92
  8. package/lib/coupon-server.cjs +1 -1
  9. package/lib/coupon-server.es.js +78 -61
  10. package/lib/coupons.cjs +1 -1
  11. package/lib/coupons.d.ts +9 -0
  12. package/lib/coupons.es.js +11 -2
  13. package/lib/currency-sync.cjs +1 -1
  14. package/lib/currency-sync.es.js +1 -1
  15. package/lib/freemius-coupons.cjs +1 -1
  16. package/lib/freemius-coupons.es.js +88 -92
  17. package/lib/freemius-license-claim.cjs +1 -1
  18. package/lib/freemius-license-claim.d.ts +13 -0
  19. package/lib/freemius-license-claim.es.js +44 -29
  20. package/lib/freemius-license.cjs +1 -1
  21. package/lib/freemius-license.es.js +19 -17
  22. package/lib/freemius-order-sync.cjs +1 -1
  23. package/lib/freemius-order-sync.d.ts +44 -0
  24. package/lib/freemius-order-sync.es.js +164 -77
  25. package/lib/freemius-pricing-server.cjs +1 -0
  26. package/lib/freemius-pricing-server.d.ts +65 -0
  27. package/lib/freemius-pricing-server.es.js +82 -0
  28. package/lib/freemius-pricing.cjs +1 -0
  29. package/lib/freemius-pricing.d.ts +53 -0
  30. package/lib/freemius-pricing.es.js +51 -0
  31. package/lib/invoice-server.cjs +1 -1
  32. package/lib/invoice-server.es.js +1 -0
  33. package/lib/pages/cms/coupons/CouponsPage.cjs +1 -1
  34. package/lib/pages/cms/coupons/CouponsPage.es.js +1 -0
  35. package/lib/pages/cms/coupons/EditCouponPage.cjs +1 -1
  36. package/lib/pages/cms/coupons/EditCouponPage.es.js +1 -0
  37. package/lib/pages/cms/coupons/actions.cjs +1 -1
  38. package/lib/pages/cms/coupons/actions.es.js +1 -0
  39. package/lib/pages/cms/orders/actions.cjs +1 -1
  40. package/lib/pages/cms/orders/actions.es.js +1 -0
  41. package/lib/pages/cms/orders/export-actions.cjs +1 -1
  42. package/lib/pages/cms/orders/export-actions.es.js +1 -0
  43. package/lib/pages/cms/orders/server-actions.cjs +1 -1
  44. package/lib/pages/cms/orders/server-actions.es.js +1 -0
  45. package/lib/pages/cms/products/ProductsPage.cjs +1 -1
  46. package/lib/pages/cms/products/ProductsPage.es.js +1 -0
  47. package/lib/pages/cms/products/[id]/edit/EditProductPage.cjs +1 -1
  48. package/lib/pages/cms/products/[id]/edit/EditProductPage.es.js +1 -0
  49. package/lib/pages/cms/products/actions.cjs +3 -3
  50. package/lib/pages/cms/products/actions.d.ts +11 -5
  51. package/lib/pages/cms/products/actions.es.js +45 -12
  52. package/lib/pages/cms/products/inventory/actions.cjs +1 -1
  53. package/lib/pages/cms/products/inventory/actions.es.js +1 -0
  54. package/lib/pages/cms/products/new/NewProductPage.cjs +1 -1
  55. package/lib/pages/cms/products/new/NewProductPage.es.js +1 -0
  56. package/lib/pages/cms/products/server-actions.cjs +1 -1
  57. package/lib/pages/cms/products/server-actions.es.js +1 -0
  58. package/lib/pages/cms/shipping/ShippingPage.cjs +1 -1
  59. package/lib/pages/cms/shipping/ShippingPage.es.js +1 -0
  60. package/lib/pages/cms/shipping/server-actions.cjs +1 -1
  61. package/lib/pages/cms/shipping/server-actions.es.js +1 -0
  62. package/lib/pages/cms/taxes/TaxesPage.cjs +1 -1
  63. package/lib/pages/cms/taxes/TaxesPage.es.js +1 -0
  64. package/lib/payment-config.cjs +1 -1
  65. package/lib/payment-config.es.js +1 -0
  66. package/lib/providers/freemius.cjs +1 -1
  67. package/lib/providers/freemius.es.js +200 -187
  68. package/lib/providers/stripe.cjs +1 -1
  69. package/lib/providers/stripe.es.js +151 -150
  70. package/lib/server-actions/coupon-actions.cjs +1 -1
  71. package/lib/server-actions/coupon-actions.es.js +1 -0
  72. package/lib/server-actions/customer-actions.d.ts +6 -1
  73. package/lib/server-actions/require-ecom-role.cjs +1 -1
  74. package/lib/server-actions/require-ecom-role.es.js +22 -10
  75. package/lib/server-actions/tax-actions.cjs +1 -1
  76. package/lib/server-actions/tax-actions.es.js +1 -0
  77. package/lib/shared-inventory.cjs +1 -1
  78. package/lib/shared-inventory.es.js +1 -1
  79. package/lib/stripe/checkout.cjs +1 -1
  80. package/lib/stripe/checkout.es.js +1 -0
  81. package/lib/stripe/order-sync.cjs +1 -1
  82. package/lib/stripe/order-sync.es.js +1 -0
  83. package/lib/stripe/webhooks.cjs +1 -1
  84. package/lib/stripe/webhooks.d.ts +10 -0
  85. package/lib/stripe/webhooks.es.js +23 -10
  86. package/package.json +4 -4
  87. package/server.cjs +1 -1
  88. package/server.es.js +31 -31
@@ -1 +1 @@
1
- const e=require("./payment-config.cjs"),t=require("./providers/freemius.cjs");let n=require("@nextblock-cms/utils");function r(e){if(!e)return null;let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toISOString().replace(`T`,` `).replace(/\.\d{3}Z$/,``)}function i(e){return e===`percent`?`percentage`:`dollar`}function a(e){return t.resolveFreemiusCheckoutCredentials(e).apiKey||t.readFreemiusEnvValue(`FREEMIUS_API_KEY`)}async function o(t){await e.hydrateFreemiusEnvFromDb();let n=a(t.productId);if(!n)throw Error(`Missing Freemius API bearer token for product ${t.productId}. Set FREEMIUS_API_KEY or FREEMIUS_CHECKOUT_PRODUCTS_JSON[${t.productId}].apiKey.`);let r=t.couponId?`/${t.couponId}`:``,i=await fetch(`https://api.freemius.com/v1/products/${t.productId}/coupons${r}.json`,{method:t.method,headers:{Authorization:`Bearer ${n}`,"Content-Type":`application/json`,Accept:`application/json`},body:t.method===`DELETE`?void 0:JSON.stringify(t.body||{})}),o=await i.text(),s=o?JSON.parse(o):null;if(!i.ok)throw Error(s?.message||s?.error?.message||`Freemius coupon request failed with ${i.status}`);return s}function s(e,t){return{code:e.code,discount:e.discount_type===`fixed`?(0,n.minorUnitAmountToMajor)(e.discount_amount,`USD`):e.discount_amount,discount_type:i(e.discount_type),plans:t.planIds.length>0?t.planIds.join(`,`):null,licenses:null,billing_cycles:null,start_date:r(e.starts_at),end_date:r(e.ends_at),redemptions_limit:e.redemption_limit??null,has_renewals_discount:!1,has_addons_discount:!1,is_one_per_user:!1,is_active:e.is_active,user_type:`all`}}async function c(e,t){if(t.provider_scope===`stripe`)return[];let{data:n,error:r}=await e.from(`coupon_products`).select(`product_id`).eq(`coupon_id`,t.id);if(r)throw Error(r.message);let i=(n||[]).map(e=>e.product_id),a=e.from(`products`).select(`id, freemius_product_id, freemius_plan_id`).eq(`payment_provider`,`freemius`).not(`freemius_product_id`,`is`,null);i.length>0&&(a=a.in(`id`,i));let{data:o,error:s}=await a;if(s)throw Error(s.message);let c=new Map;for(let e of o||[]){let t=String(e.freemius_product_id||``).trim();if(!t)continue;let n=c.get(t)??{freemiusProductId:t,productId:e.id,planIds:[]};i.length>0&&e.freemius_plan_id&&n.planIds.push(String(e.freemius_plan_id)),c.set(t,n)}return[...c.values()].map(e=>({...e,planIds:[...new Set(e.planIds)]}))}async function l(e,t){let{data:n}=await e.from(`coupon_freemius_mappings`).select(`sync_status, sync_error`).eq(`coupon_id`,t),r=n||[];if(r.length===0){await e.from(`coupons`).update({freemius_sync_status:`not_required`,freemius_sync_error:null}).eq(`id`,t);return}let i=r.find(e=>e.sync_status===`failed`);await e.from(`coupons`).update({freemius_sync_status:i?`failed`:`synced`,freemius_sync_error:i?.sync_error??null}).eq(`id`,t)}async function u(e){let{data:t,error:n}=await e.client.from(`coupons`).select(`id, code, name, internal_note, provider_scope, discount_type, discount_amount, is_active, starts_at, ends_at, redemption_limit`).eq(`id`,e.couponId).single();if(n||!t)return{success:!1,error:n?.message||`Coupon not found`};let r=t,i=await c(e.client,r);await e.client.from(`coupons`).update({freemius_sync_status:i.length>0?`pending`:`not_required`,freemius_sync_error:null}).eq(`id`,r.id);for(let t of i){let{data:n}=await e.client.from(`coupon_freemius_mappings`).select(`id, freemius_coupon_id`).eq(`coupon_id`,r.id).eq(`freemius_product_id`,t.freemiusProductId).maybeSingle(),i=s(r,t);try{let a=await o({productId:t.freemiusProductId,method:n?.freemius_coupon_id?`PUT`:`POST`,couponId:n?.freemius_coupon_id??null,body:i}),s=a?.coupon??a;await e.client.from(`coupon_freemius_mappings`).upsert({id:n?.id,coupon_id:r.id,product_id:t.productId,freemius_product_id:t.freemiusProductId,freemius_coupon_id:s?.id?String(s.id):n?.freemius_coupon_id??null,freemius_coupon_code:r.code,sync_status:`synced`,sync_error:null,remote_payload:a,last_synced_at:new Date().toISOString()},{onConflict:`coupon_id,freemius_product_id`})}catch(i){await e.client.from(`coupon_freemius_mappings`).upsert({id:n?.id,coupon_id:r.id,product_id:t.productId,freemius_product_id:t.freemiusProductId,freemius_coupon_id:n?.freemius_coupon_id??null,freemius_coupon_code:r.code,sync_status:`failed`,sync_error:i.message||`Freemius sync failed`,last_synced_at:new Date().toISOString()},{onConflict:`coupon_id,freemius_product_id`})}}return await l(e.client,r.id),{success:!0,targetCount:i.length}}function d(e){let t=(e.sku||``).toUpperCase().replace(/[^A-Z0-9]/g,``);return t?`SALE${t}`.slice(0,32):`SALE${e.productId.replace(/[^A-Za-z0-9]/g,``).toUpperCase()}`.slice(0,32)}function f(e,t){if(typeof e!=`number`||e<=0||typeof t!=`number`||t<0||t>=e)return null;let n=Math.round((1-t/e)*100);return n<=0||n>100?null:n}async function p(e){let{data:t,error:n}=await e.client.from(`products`).select(`id, sku, price, sale_price, sale_start_at, sale_end_at, payment_provider, freemius_product_id, freemius_plan_id`).eq(`id`,e.productId).maybeSingle();if(n||!t)return{success:!1,error:n?.message||`Product not found`};let r=t,i=String(r.freemius_product_id||``).trim();if(r.payment_provider!==`freemius`||!i)return{success:!0,skipped:!0,reason:`not_a_freemius_product`};let a=f(r.price,r.sale_price),c=a!==null,{data:l}=await e.client.from(`product_freemius_sale_coupons`).select(`id, freemius_coupon_id, freemius_coupon_code, discount_percent, is_active`).eq(`product_id`,r.id).maybeSingle();if(!c&&!l?.freemius_coupon_id)return l?.id&&await e.client.from(`product_freemius_sale_coupons`).update({is_active:!1,updated_at:new Date().toISOString()}).eq(`id`,l.id),{success:!0,active:!1};let u=l?.freemius_coupon_code||d({sku:r.sku,productId:r.id}),p=r.freemius_plan_id?[String(r.freemius_plan_id)]:[],m=a??l?.discount_percent??1,h=s({id:r.id,code:u,name:`Scheduled sale ${r.sku||r.id}`,provider_scope:`freemius`,discount_type:`percent`,discount_amount:m,is_active:c,starts_at:r.sale_start_at,ends_at:r.sale_end_at,redemption_limit:null},{freemiusProductId:i,productId:r.id,planIds:p});try{let t=await o({productId:i,method:l?.freemius_coupon_id?`PUT`:`POST`,couponId:l?.freemius_coupon_id??null,body:h}),n=t?.coupon??t;return await e.client.from(`product_freemius_sale_coupons`).upsert({id:l?.id,product_id:r.id,freemius_product_id:i,freemius_plan_id:r.freemius_plan_id?String(r.freemius_plan_id):null,freemius_coupon_id:n?.id?String(n.id):l?.freemius_coupon_id??null,freemius_coupon_code:u,discount_percent:a,starts_at:r.sale_start_at,ends_at:r.sale_end_at,is_active:c,sync_status:`synced`,sync_error:null,remote_payload:t,last_synced_at:new Date().toISOString()},{onConflict:`product_id`}),{success:!0,active:c,code:u}}catch(t){return await e.client.from(`product_freemius_sale_coupons`).upsert({id:l?.id,product_id:r.id,freemius_product_id:i,freemius_plan_id:r.freemius_plan_id?String(r.freemius_plan_id):null,freemius_coupon_id:l?.freemius_coupon_id??null,freemius_coupon_code:u,discount_percent:a,starts_at:r.sale_start_at,ends_at:r.sale_end_at,is_active:c,sync_status:`failed`,sync_error:t.message||`Freemius sale coupon sync failed`,last_synced_at:new Date().toISOString()},{onConflict:`product_id`}),{success:!1,error:t.message||`Freemius sale coupon sync failed`}}}async function m(e){let{data:t}=await e.client.from(`coupon_freemius_mappings`).select(`id, freemius_product_id, freemius_coupon_id`).eq(`coupon_id`,e.couponId).not(`freemius_coupon_id`,`is`,null);for(let n of t||[])try{await o({productId:n.freemius_product_id,couponId:n.freemius_coupon_id,method:`DELETE`}),await e.client.from(`coupon_freemius_mappings`).update({sync_status:`deleted`,sync_error:null,updated_at:new Date().toISOString()}).eq(`id`,n.id)}catch(t){await e.client.from(`coupon_freemius_mappings`).update({sync_status:`failed`,sync_error:t.message||`Freemius delete failed`,updated_at:new Date().toISOString()}).eq(`id`,n.id)}}exports.deleteCouponFromFreemius=m,exports.syncCouponToFreemius=u,exports.syncProductSaleCouponToFreemius=p;
1
+ const e=require("./freemius-pricing.cjs"),t=require("./payment-config.cjs"),n=require("./providers/freemius.cjs");let r=require("@nextblock-cms/utils");function i(e){if(!e)return null;let t=new Date(e);return Number.isNaN(t.getTime())?e:t.toISOString().replace(`T`,` `).replace(/\.\d{3}Z$/,``)}function a(e){return e===`percent`?`percentage`:`dollar`}function o(e){return n.resolveFreemiusCheckoutCredentials(e).apiKey||n.readFreemiusEnvValue(`FREEMIUS_API_KEY`)}async function s(e){await t.hydrateFreemiusEnvFromDb();let n=o(e.productId);if(!n)throw Error(`Missing Freemius API bearer token for product ${e.productId}. Set FREEMIUS_API_KEY or FREEMIUS_CHECKOUT_PRODUCTS_JSON[${e.productId}].apiKey.`);let r=e.couponId?`/${e.couponId}`:``,i=await fetch(`https://api.freemius.com/v1/products/${e.productId}/coupons${r}.json`,{method:e.method,headers:{Authorization:`Bearer ${n}`,"Content-Type":`application/json`,Accept:`application/json`},body:e.method===`DELETE`?void 0:JSON.stringify(e.body||{})}),a=await i.text(),s=a?JSON.parse(a):null;if(!i.ok)throw Error(s?.message||s?.error?.message||`Freemius coupon request failed with ${i.status}`);return s}function c(e,t){return{code:e.code,discount:e.discount_type===`fixed`?(0,r.minorUnitAmountToMajor)(e.discount_amount,`USD`):e.discount_amount,discount_type:a(e.discount_type),plans:t.planIds.length>0?t.planIds.join(`,`):null,licenses:null,billing_cycles:null,start_date:i(e.starts_at),end_date:i(e.ends_at),redemptions_limit:e.redemption_limit??null,has_renewals_discount:!1,has_addons_discount:!1,is_one_per_user:!1,is_active:e.is_active,user_type:`all`}}async function l(e,t){if(t.provider_scope===`stripe`)return[];let{data:n,error:r}=await e.from(`coupon_products`).select(`product_id`).eq(`coupon_id`,t.id);if(r)throw Error(r.message);let i=(n||[]).map(e=>e.product_id),a=e.from(`products`).select(`id, freemius_product_id, freemius_plan_id`).eq(`payment_provider`,`freemius`).not(`freemius_product_id`,`is`,null);i.length>0&&(a=a.in(`id`,i));let{data:o,error:s}=await a;if(s)throw Error(s.message);let c=new Map;for(let e of o||[]){let t=String(e.freemius_product_id||``).trim();if(!t)continue;let n=c.get(t)??{freemiusProductId:t,productId:e.id,planIds:[]};i.length>0&&e.freemius_plan_id&&n.planIds.push(String(e.freemius_plan_id)),c.set(t,n)}return[...c.values()].map(e=>({...e,planIds:[...new Set(e.planIds)]}))}async function u(e,t){let{data:n}=await e.from(`coupon_freemius_mappings`).select(`sync_status, sync_error`).eq(`coupon_id`,t),r=n||[];if(r.length===0){await e.from(`coupons`).update({freemius_sync_status:`not_required`,freemius_sync_error:null}).eq(`id`,t);return}let i=r.find(e=>e.sync_status===`failed`);await e.from(`coupons`).update({freemius_sync_status:i?`failed`:`synced`,freemius_sync_error:i?.sync_error??null}).eq(`id`,t)}async function d(e){let{data:t,error:n}=await e.client.from(`coupons`).select(`id, code, name, internal_note, provider_scope, discount_type, discount_amount, is_active, starts_at, ends_at, redemption_limit`).eq(`id`,e.couponId).single();if(n||!t)return{success:!1,error:n?.message||`Coupon not found`};let r=t,i=await l(e.client,r);await e.client.from(`coupons`).update({freemius_sync_status:i.length>0?`pending`:`not_required`,freemius_sync_error:null}).eq(`id`,r.id);for(let t of i){let{data:n}=await e.client.from(`coupon_freemius_mappings`).select(`id, freemius_coupon_id`).eq(`coupon_id`,r.id).eq(`freemius_product_id`,t.freemiusProductId).maybeSingle(),i=c(r,t);try{let a=await s({productId:t.freemiusProductId,method:n?.freemius_coupon_id?`PUT`:`POST`,couponId:n?.freemius_coupon_id??null,body:i}),o=a?.coupon??a;await e.client.from(`coupon_freemius_mappings`).upsert({id:n?.id,coupon_id:r.id,product_id:t.productId,freemius_product_id:t.freemiusProductId,freemius_coupon_id:o?.id?String(o.id):n?.freemius_coupon_id??null,freemius_coupon_code:r.code,sync_status:`synced`,sync_error:null,remote_payload:a,last_synced_at:new Date().toISOString()},{onConflict:`coupon_id,freemius_product_id`})}catch(i){await e.client.from(`coupon_freemius_mappings`).upsert({id:n?.id,coupon_id:r.id,product_id:t.productId,freemius_product_id:t.freemiusProductId,freemius_coupon_id:n?.freemius_coupon_id??null,freemius_coupon_code:r.code,sync_status:`failed`,sync_error:i.message||`Freemius sync failed`,last_synced_at:new Date().toISOString()},{onConflict:`coupon_id,freemius_product_id`})}}return await u(e.client,r.id),{success:!0,targetCount:i.length}}function f(e){let t=(e.sku||``).toUpperCase().replace(/[^A-Z0-9]/g,``);return t?`SALE${t}`.slice(0,32):`SALE${e.productId.replace(/[^A-Za-z0-9]/g,``).toUpperCase()}`.slice(0,32)}async function p(t){let{data:n,error:r}=await t.client.from(`products`).select(`id, sku, price, sale_price, sale_start_at, sale_end_at, payment_provider, freemius_product_id, freemius_plan_id`).eq(`id`,t.productId).maybeSingle();if(r||!n)return{success:!1,error:r?.message||`Product not found`};let i=n,a=String(i.freemius_product_id||``).trim();if(i.payment_provider!==`freemius`||!a)return{success:!0,skipped:!0,reason:`not_a_freemius_product`};let o=e.computeFreemiusSaleDiscountPercent(i.price,i.sale_price),l=o!==null,{data:u}=await t.client.from(`product_freemius_sale_coupons`).select(`id, freemius_coupon_id, freemius_coupon_code, discount_percent, is_active`).eq(`product_id`,i.id).maybeSingle();if(!l&&!u?.freemius_coupon_id)return u?.id&&await t.client.from(`product_freemius_sale_coupons`).update({is_active:!1,updated_at:new Date().toISOString()}).eq(`id`,u.id),{success:!0,active:!1};let d=u?.freemius_coupon_code||f({sku:i.sku,productId:i.id}),p=i.freemius_plan_id?[String(i.freemius_plan_id)]:[],m=o??u?.discount_percent??1,h=c({id:i.id,code:d,name:`Scheduled sale ${i.sku||i.id}`,provider_scope:`freemius`,discount_type:`percent`,discount_amount:m,is_active:l,starts_at:i.sale_start_at,ends_at:i.sale_end_at,redemption_limit:null},{freemiusProductId:a,productId:i.id,planIds:p});try{let e=await s({productId:a,method:u?.freemius_coupon_id?`PUT`:`POST`,couponId:u?.freemius_coupon_id??null,body:h}),n=e?.coupon??e;return await t.client.from(`product_freemius_sale_coupons`).upsert({id:u?.id,product_id:i.id,freemius_product_id:a,freemius_plan_id:i.freemius_plan_id?String(i.freemius_plan_id):null,freemius_coupon_id:n?.id?String(n.id):u?.freemius_coupon_id??null,freemius_coupon_code:d,discount_percent:o,starts_at:i.sale_start_at,ends_at:i.sale_end_at,is_active:l,sync_status:`synced`,sync_error:null,remote_payload:e,last_synced_at:new Date().toISOString()},{onConflict:`product_id`}),{success:!0,active:l,code:d}}catch(e){return await t.client.from(`product_freemius_sale_coupons`).upsert({id:u?.id,product_id:i.id,freemius_product_id:a,freemius_plan_id:i.freemius_plan_id?String(i.freemius_plan_id):null,freemius_coupon_id:u?.freemius_coupon_id??null,freemius_coupon_code:d,discount_percent:o,starts_at:i.sale_start_at,ends_at:i.sale_end_at,is_active:l,sync_status:`failed`,sync_error:e.message||`Freemius sale coupon sync failed`,last_synced_at:new Date().toISOString()},{onConflict:`product_id`}),{success:!1,error:e.message||`Freemius sale coupon sync failed`}}}async function m(e){let{data:t}=await e.client.from(`coupon_freemius_mappings`).select(`id, freemius_product_id, freemius_coupon_id`).eq(`coupon_id`,e.couponId).not(`freemius_coupon_id`,`is`,null);for(let n of t||[])try{await s({productId:n.freemius_product_id,couponId:n.freemius_coupon_id,method:`DELETE`}),await e.client.from(`coupon_freemius_mappings`).update({sync_status:`deleted`,sync_error:null,updated_at:new Date().toISOString()}).eq(`id`,n.id)}catch(t){await e.client.from(`coupon_freemius_mappings`).update({sync_status:`failed`,sync_error:t.message||`Freemius delete failed`,updated_at:new Date().toISOString()}).eq(`id`,n.id)}}exports.deleteCouponFromFreemius=m,exports.syncCouponToFreemius=d,exports.syncProductSaleCouponToFreemius=p;
@@ -1,44 +1,45 @@
1
- import { hydrateFreemiusEnvFromDb as e } from "./payment-config.es.js";
2
- import { readFreemiusEnvValue as t, resolveFreemiusCheckoutCredentials as n } from "./providers/freemius.es.js";
3
- import { minorUnitAmountToMajor as r } from "@nextblock-cms/utils";
1
+ import { computeFreemiusSaleDiscountPercent as e } from "./freemius-pricing.es.js";
2
+ import { hydrateFreemiusEnvFromDb as t } from "./payment-config.es.js";
3
+ import { readFreemiusEnvValue as n, resolveFreemiusCheckoutCredentials as r } from "./providers/freemius.es.js";
4
+ import { minorUnitAmountToMajor as i } from "@nextblock-cms/utils";
4
5
  //#region src/lib/freemius-coupons.ts
5
- function i(e) {
6
+ function a(e) {
6
7
  if (!e) return null;
7
8
  let t = new Date(e);
8
9
  return Number.isNaN(t.getTime()) ? e : t.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "");
9
10
  }
10
- function a(e) {
11
+ function o(e) {
11
12
  return e === "percent" ? "percentage" : "dollar";
12
13
  }
13
- function o(e) {
14
- return n(e).apiKey || t("FREEMIUS_API_KEY");
14
+ function s(e) {
15
+ return r(e).apiKey || n("FREEMIUS_API_KEY");
15
16
  }
16
- async function s(t) {
17
- await e();
18
- let n = o(t.productId);
19
- if (!n) throw Error(`Missing Freemius API bearer token for product ${t.productId}. Set FREEMIUS_API_KEY or FREEMIUS_CHECKOUT_PRODUCTS_JSON[${t.productId}].apiKey.`);
20
- let r = t.couponId ? `/${t.couponId}` : "", i = await fetch(`https://api.freemius.com/v1/products/${t.productId}/coupons${r}.json`, {
21
- method: t.method,
17
+ async function c(e) {
18
+ await t();
19
+ let n = s(e.productId);
20
+ if (!n) throw Error(`Missing Freemius API bearer token for product ${e.productId}. Set FREEMIUS_API_KEY or FREEMIUS_CHECKOUT_PRODUCTS_JSON[${e.productId}].apiKey.`);
21
+ let r = e.couponId ? `/${e.couponId}` : "", i = await fetch(`https://api.freemius.com/v1/products/${e.productId}/coupons${r}.json`, {
22
+ method: e.method,
22
23
  headers: {
23
24
  Authorization: `Bearer ${n}`,
24
25
  "Content-Type": "application/json",
25
26
  Accept: "application/json"
26
27
  },
27
- body: t.method === "DELETE" ? void 0 : JSON.stringify(t.body || {})
28
- }), a = await i.text(), s = a ? JSON.parse(a) : null;
29
- if (!i.ok) throw Error(s?.message || s?.error?.message || `Freemius coupon request failed with ${i.status}`);
30
- return s;
28
+ body: e.method === "DELETE" ? void 0 : JSON.stringify(e.body || {})
29
+ }), a = await i.text(), o = a ? JSON.parse(a) : null;
30
+ if (!i.ok) throw Error(o?.message || o?.error?.message || `Freemius coupon request failed with ${i.status}`);
31
+ return o;
31
32
  }
32
- function c(e, t) {
33
+ function l(e, t) {
33
34
  return {
34
35
  code: e.code,
35
- discount: e.discount_type === "fixed" ? r(e.discount_amount, "USD") : e.discount_amount,
36
- discount_type: a(e.discount_type),
36
+ discount: e.discount_type === "fixed" ? i(e.discount_amount, "USD") : e.discount_amount,
37
+ discount_type: o(e.discount_type),
37
38
  plans: t.planIds.length > 0 ? t.planIds.join(",") : null,
38
39
  licenses: null,
39
40
  billing_cycles: null,
40
- start_date: i(e.starts_at),
41
- end_date: i(e.ends_at),
41
+ start_date: a(e.starts_at),
42
+ end_date: a(e.ends_at),
42
43
  redemptions_limit: e.redemption_limit ?? null,
43
44
  has_renewals_discount: !1,
44
45
  has_addons_discount: !1,
@@ -47,7 +48,7 @@ function c(e, t) {
47
48
  user_type: "all"
48
49
  };
49
50
  }
50
- async function l(e, t) {
51
+ async function u(e, t) {
51
52
  if (t.provider_scope === "stripe") return [];
52
53
  let { data: n, error: r } = await e.from("coupon_products").select("product_id").eq("coupon_id", t.id);
53
54
  if (r) throw Error(r.message);
@@ -71,7 +72,7 @@ async function l(e, t) {
71
72
  planIds: [...new Set(e.planIds)]
72
73
  }));
73
74
  }
74
- async function u(e, t) {
75
+ async function d(e, t) {
75
76
  let { data: n } = await e.from("coupon_freemius_mappings").select("sync_status, sync_error").eq("coupon_id", t), r = n || [];
76
77
  if (r.length === 0) {
77
78
  await e.from("coupons").update({
@@ -86,21 +87,21 @@ async function u(e, t) {
86
87
  freemius_sync_error: i?.sync_error ?? null
87
88
  }).eq("id", t);
88
89
  }
89
- async function d(e) {
90
+ async function f(e) {
90
91
  let { data: t, error: n } = await e.client.from("coupons").select("id, code, name, internal_note, provider_scope, discount_type, discount_amount, is_active, starts_at, ends_at, redemption_limit").eq("id", e.couponId).single();
91
92
  if (n || !t) return {
92
93
  success: !1,
93
94
  error: n?.message || "Coupon not found"
94
95
  };
95
- let r = t, i = await l(e.client, r);
96
+ let r = t, i = await u(e.client, r);
96
97
  await e.client.from("coupons").update({
97
98
  freemius_sync_status: i.length > 0 ? "pending" : "not_required",
98
99
  freemius_sync_error: null
99
100
  }).eq("id", r.id);
100
101
  for (let t of i) {
101
- let { data: n } = await e.client.from("coupon_freemius_mappings").select("id, freemius_coupon_id").eq("coupon_id", r.id).eq("freemius_product_id", t.freemiusProductId).maybeSingle(), i = c(r, t);
102
+ let { data: n } = await e.client.from("coupon_freemius_mappings").select("id, freemius_coupon_id").eq("coupon_id", r.id).eq("freemius_product_id", t.freemiusProductId).maybeSingle(), i = l(r, t);
102
103
  try {
103
- let a = await s({
104
+ let a = await c({
104
105
  productId: t.freemiusProductId,
105
106
  method: n?.freemius_coupon_id ? "PUT" : "POST",
106
107
  couponId: n?.freemius_coupon_id ?? null,
@@ -132,111 +133,106 @@ async function d(e) {
132
133
  }, { onConflict: "coupon_id,freemius_product_id" });
133
134
  }
134
135
  }
135
- return await u(e.client, r.id), {
136
+ return await d(e.client, r.id), {
136
137
  success: !0,
137
138
  targetCount: i.length
138
139
  };
139
140
  }
140
- function f(e) {
141
+ function p(e) {
141
142
  let t = (e.sku || "").toUpperCase().replace(/[^A-Z0-9]/g, "");
142
143
  return t ? `SALE${t}`.slice(0, 32) : `SALE${e.productId.replace(/[^A-Za-z0-9]/g, "").toUpperCase()}`.slice(0, 32);
143
144
  }
144
- function p(e, t) {
145
- if (typeof e != "number" || e <= 0 || typeof t != "number" || t < 0 || t >= e) return null;
146
- let n = Math.round((1 - t / e) * 100);
147
- return n <= 0 || n > 100 ? null : n;
148
- }
149
- async function m(e) {
150
- let { data: t, error: n } = await e.client.from("products").select("id, sku, price, sale_price, sale_start_at, sale_end_at, payment_provider, freemius_product_id, freemius_plan_id").eq("id", e.productId).maybeSingle();
151
- if (n || !t) return {
145
+ async function m(t) {
146
+ let { data: n, error: r } = await t.client.from("products").select("id, sku, price, sale_price, sale_start_at, sale_end_at, payment_provider, freemius_product_id, freemius_plan_id").eq("id", t.productId).maybeSingle();
147
+ if (r || !n) return {
152
148
  success: !1,
153
- error: n?.message || "Product not found"
149
+ error: r?.message || "Product not found"
154
150
  };
155
- let r = t, i = String(r.freemius_product_id || "").trim();
156
- if (r.payment_provider !== "freemius" || !i) return {
151
+ let i = n, a = String(i.freemius_product_id || "").trim();
152
+ if (i.payment_provider !== "freemius" || !a) return {
157
153
  success: !0,
158
154
  skipped: !0,
159
155
  reason: "not_a_freemius_product"
160
156
  };
161
- let a = p(r.price, r.sale_price), o = a !== null, { data: l } = await e.client.from("product_freemius_sale_coupons").select("id, freemius_coupon_id, freemius_coupon_code, discount_percent, is_active").eq("product_id", r.id).maybeSingle();
162
- if (!o && !l?.freemius_coupon_id) return l?.id && await e.client.from("product_freemius_sale_coupons").update({
157
+ let o = e(i.price, i.sale_price), s = o !== null, { data: u } = await t.client.from("product_freemius_sale_coupons").select("id, freemius_coupon_id, freemius_coupon_code, discount_percent, is_active").eq("product_id", i.id).maybeSingle();
158
+ if (!s && !u?.freemius_coupon_id) return u?.id && await t.client.from("product_freemius_sale_coupons").update({
163
159
  is_active: !1,
164
160
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
165
- }).eq("id", l.id), {
161
+ }).eq("id", u.id), {
166
162
  success: !0,
167
163
  active: !1
168
164
  };
169
- let u = l?.freemius_coupon_code || f({
170
- sku: r.sku,
171
- productId: r.id
172
- }), d = r.freemius_plan_id ? [String(r.freemius_plan_id)] : [], m = a ?? l?.discount_percent ?? 1, h = c({
173
- id: r.id,
174
- code: u,
175
- name: `Scheduled sale ${r.sku || r.id}`,
165
+ let d = u?.freemius_coupon_code || p({
166
+ sku: i.sku,
167
+ productId: i.id
168
+ }), f = i.freemius_plan_id ? [String(i.freemius_plan_id)] : [], m = o ?? u?.discount_percent ?? 1, h = l({
169
+ id: i.id,
170
+ code: d,
171
+ name: `Scheduled sale ${i.sku || i.id}`,
176
172
  provider_scope: "freemius",
177
173
  discount_type: "percent",
178
174
  discount_amount: m,
179
- is_active: o,
180
- starts_at: r.sale_start_at,
181
- ends_at: r.sale_end_at,
175
+ is_active: s,
176
+ starts_at: i.sale_start_at,
177
+ ends_at: i.sale_end_at,
182
178
  redemption_limit: null
183
179
  }, {
184
- freemiusProductId: i,
185
- productId: r.id,
186
- planIds: d
180
+ freemiusProductId: a,
181
+ productId: i.id,
182
+ planIds: f
187
183
  });
188
184
  try {
189
- let t = await s({
190
- productId: i,
191
- method: l?.freemius_coupon_id ? "PUT" : "POST",
192
- couponId: l?.freemius_coupon_id ?? null,
185
+ let e = await c({
186
+ productId: a,
187
+ method: u?.freemius_coupon_id ? "PUT" : "POST",
188
+ couponId: u?.freemius_coupon_id ?? null,
193
189
  body: h
194
- }), n = t?.coupon ?? t;
195
- return await e.client.from("product_freemius_sale_coupons").upsert({
196
- id: l?.id,
197
- product_id: r.id,
198
- freemius_product_id: i,
199
- freemius_plan_id: r.freemius_plan_id ? String(r.freemius_plan_id) : null,
200
- freemius_coupon_id: n?.id ? String(n.id) : l?.freemius_coupon_id ?? null,
201
- freemius_coupon_code: u,
202
- discount_percent: a,
203
- starts_at: r.sale_start_at,
204
- ends_at: r.sale_end_at,
205
- is_active: o,
190
+ }), n = e?.coupon ?? e;
191
+ return await t.client.from("product_freemius_sale_coupons").upsert({
192
+ id: u?.id,
193
+ product_id: i.id,
194
+ freemius_product_id: a,
195
+ freemius_plan_id: i.freemius_plan_id ? String(i.freemius_plan_id) : null,
196
+ freemius_coupon_id: n?.id ? String(n.id) : u?.freemius_coupon_id ?? null,
197
+ freemius_coupon_code: d,
198
+ discount_percent: o,
199
+ starts_at: i.sale_start_at,
200
+ ends_at: i.sale_end_at,
201
+ is_active: s,
206
202
  sync_status: "synced",
207
203
  sync_error: null,
208
- remote_payload: t,
204
+ remote_payload: e,
209
205
  last_synced_at: (/* @__PURE__ */ new Date()).toISOString()
210
206
  }, { onConflict: "product_id" }), {
211
207
  success: !0,
212
- active: o,
213
- code: u
208
+ active: s,
209
+ code: d
214
210
  };
215
- } catch (t) {
216
- return await e.client.from("product_freemius_sale_coupons").upsert({
217
- id: l?.id,
218
- product_id: r.id,
219
- freemius_product_id: i,
220
- freemius_plan_id: r.freemius_plan_id ? String(r.freemius_plan_id) : null,
221
- freemius_coupon_id: l?.freemius_coupon_id ?? null,
222
- freemius_coupon_code: u,
223
- discount_percent: a,
224
- starts_at: r.sale_start_at,
225
- ends_at: r.sale_end_at,
226
- is_active: o,
211
+ } catch (e) {
212
+ return await t.client.from("product_freemius_sale_coupons").upsert({
213
+ id: u?.id,
214
+ product_id: i.id,
215
+ freemius_product_id: a,
216
+ freemius_plan_id: i.freemius_plan_id ? String(i.freemius_plan_id) : null,
217
+ freemius_coupon_id: u?.freemius_coupon_id ?? null,
218
+ freemius_coupon_code: d,
219
+ discount_percent: o,
220
+ starts_at: i.sale_start_at,
221
+ ends_at: i.sale_end_at,
222
+ is_active: s,
227
223
  sync_status: "failed",
228
- sync_error: t.message || "Freemius sale coupon sync failed",
224
+ sync_error: e.message || "Freemius sale coupon sync failed",
229
225
  last_synced_at: (/* @__PURE__ */ new Date()).toISOString()
230
226
  }, { onConflict: "product_id" }), {
231
227
  success: !1,
232
- error: t.message || "Freemius sale coupon sync failed"
228
+ error: e.message || "Freemius sale coupon sync failed"
233
229
  };
234
230
  }
235
231
  }
236
232
  async function h(e) {
237
233
  let { data: t } = await e.client.from("coupon_freemius_mappings").select("id, freemius_product_id, freemius_coupon_id").eq("coupon_id", e.couponId).not("freemius_coupon_id", "is", null);
238
234
  for (let n of t || []) try {
239
- await s({
235
+ await c({
240
236
  productId: n.freemius_product_id,
241
237
  couponId: n.freemius_coupon_id,
242
238
  method: "DELETE"
@@ -254,4 +250,4 @@ async function h(e) {
254
250
  }
255
251
  }
256
252
  //#endregion
257
- export { h as deleteCouponFromFreemius, d as syncCouponToFreemius, m as syncProductSaleCouponToFreemius };
253
+ export { h as deleteCouponFromFreemius, f as syncCouponToFreemius, m as syncProductSaleCouponToFreemius };
@@ -1 +1 @@
1
- const e=require("./payment-config.cjs"),t=require("./providers/freemius.cjs");let n=require("@freemius/sdk");var r=20,i=`This license cannot be claimed automatically. Use the key from your purchase email.`;function a(e){if(!e||typeof e!=`string`)return null;let t=e.trim(),n=/(?:z|[+-]\d{2}:?\d{2})$/i.test(t)?t:`${t.replace(` `,`T`)}Z`,r=Date.parse(n);return Number.isFinite(r)?r:null}function o(e,t){return e==null||t==null?!1:String(e).trim()===String(t).trim()}function s(e){return(e??``).trim().toLowerCase()}function c(e){let{license:t,request:n,user:r}=e,i=e.maxAgeMinutes??20,c=(e.now??new Date).getTime();if(!t||!o(t.id,n.licenseId))return{ok:!1,reason:`license_not_found`};let l=a(t.created);return l===null||c-l>i*6e4||l-c>3e5?{ok:!1,reason:`too_old`}:o(t.plugin_id,n.productId)?t.is_cancelled?{ok:!1,reason:`cancelled`}:!n.userId?.trim()||!o(t.user_id,n.userId)?{ok:!1,reason:`user_mismatch`}:!r||!s(n.email)||s(r.email)!==s(n.email)?{ok:!1,reason:`email_mismatch`}:typeof t.activated==`number`&&t.activated>0?{ok:!1,reason:`already_activated`}:t.secret_key?{ok:!0}:{ok:!1,reason:`no_key`}:{ok:!1,reason:`product_mismatch`}}async function l(r,a){await e.hydrateFreemiusEnvFromDb();let o=t.resolveFreemiusCheckoutCredentials(r.productId);if(!o.apiKey||!o.secretKey||!o.publicKey)return{error:`The license service is not configured for this product.`,ok:!1,reason:`not_configured`,status:503};let s=new n.Freemius({apiKey:o.apiKey,productId:Number(r.productId),publicKey:o.publicKey,secretKey:o.secretKey}),l=null,u=null;try{l=await s.api.license.retrieve(r.licenseId),l?.user_id!==null&&l?.user_id!==void 0&&(u=await s.api.user.retrieve(String(l.user_id)))}catch(e){return console.error(`[Freemius License Claim] Freemius lookup failed:`,e),{error:`Freemius could not be reached to verify the license.`,ok:!1,reason:`upstream_error`,status:502}}let d=c({license:l,maxAgeMinutes:a?.maxAgeMinutes,now:a?.now,request:r,user:u});return d.ok?{expiration:l?.expiration??null,licenseKey:String(l?.secret_key),ok:!0,planId:l?.plan_id!==null&&l?.plan_id!==void 0?String(l.plan_id):null}:{error:i,ok:!1,reason:d.reason,status:403}}exports.FREEMIUS_LICENSE_CLAIM_MAX_AGE_MINUTES=r,exports.FREEMIUS_LICENSE_CLAIM_REFUSED_MESSAGE=i,exports.claimFreemiusLicenseKey=l,exports.evaluateFreemiusLicenseClaim=c,exports.parseFreemiusTimestamp=a;
1
+ const e=require("./payment-config.cjs"),t=require("./providers/freemius.cjs");let n=require("@freemius/sdk");var r=20,i=`This license cannot be claimed automatically. Use the key from your purchase email.`;function a(e){if(!e||typeof e!=`string`)return null;let t=e.trim(),n=/(?:z|[+-]\d{2}:?\d{2})$/i.test(t)?t:`${t.replace(` `,`T`)}Z`,r=Date.parse(n);return Number.isFinite(r)?r:null}function o(e,t){return e==null||t==null?!1:String(e).trim()===String(t).trim()}function s(e){return(e??``).trim().toLowerCase()}function c(e){let{license:t,request:n,user:r}=e,i=e.maxAgeMinutes??20,c=(e.now??new Date).getTime();if(!t||!o(t.id,n.licenseId))return{ok:!1,reason:`license_not_found`};let l=a(t.created);return l===null||c-l>i*6e4||l-c>3e5?{ok:!1,reason:`too_old`}:o(t.plugin_id,n.productId)?t.is_cancelled?{ok:!1,reason:`cancelled`}:!n.userId?.trim()||!o(t.user_id,n.userId)?{ok:!1,reason:`user_mismatch`}:!r||!s(n.email)||s(r.email)!==s(n.email)?{ok:!1,reason:`email_mismatch`}:typeof t.activated==`number`&&t.activated>0?{ok:!1,reason:`already_activated`}:t.secret_key?{ok:!0}:{ok:!1,reason:`no_key`}:{ok:!1,reason:`product_mismatch`}}async function l(r,i){await e.hydrateFreemiusEnvFromDb();let a=t.resolveFreemiusCheckoutCredentials(r);if(!a.apiKey||!a.secretKey||!a.publicKey)return{ok:!1,reason:`not_configured`};let o=new n.Freemius({apiKey:a.apiKey,productId:Number(r),publicKey:a.publicKey,secretKey:a.secretKey});try{let e=await o.api.license.retrieve(i),t=null;return e?.user_id!==null&&e?.user_id!==void 0&&(t=await o.api.user.retrieve(String(e.user_id))),{license:e,ok:!0,user:t}}catch(e){return console.error(`[Freemius License] Freemius lookup failed:`,e),{ok:!1,reason:`upstream_error`}}}async function u(e,t){let n=await l(e.productId,e.licenseId);if(!n.ok)return n.reason===`not_configured`?{error:`The license service is not configured for this product.`,ok:!1,reason:`not_configured`,status:503}:{error:`Freemius could not be reached to verify the license.`,ok:!1,reason:`upstream_error`,status:502};let{license:r,user:a}=n,o=c({license:r,maxAgeMinutes:t?.maxAgeMinutes,now:t?.now,request:e,user:a});return o.ok?{expiration:r?.expiration??null,licenseKey:String(r?.secret_key),ok:!0,planId:r?.plan_id!==null&&r?.plan_id!==void 0?String(r.plan_id):null}:{error:i,ok:!1,reason:o.reason,status:403}}exports.FREEMIUS_LICENSE_CLAIM_MAX_AGE_MINUTES=r,exports.FREEMIUS_LICENSE_CLAIM_REFUSED_MESSAGE=i,exports.claimFreemiusLicenseKey=u,exports.evaluateFreemiusLicenseClaim=c,exports.parseFreemiusTimestamp=a,exports.retrieveFreemiusLicenseRecords=l;
@@ -83,6 +83,19 @@ export type FreemiusLicenseClaimResult = {
83
83
  reason: FreemiusLicenseClaimRejection | 'not_configured' | 'upstream_error';
84
84
  status: number;
85
85
  };
86
+ export type FreemiusLicenseRecords = {
87
+ license: FreemiusLicenseRecordLike | null;
88
+ ok: true;
89
+ user: FreemiusUserRecordLike | null;
90
+ } | {
91
+ ok: false;
92
+ reason: 'not_configured' | 'upstream_error';
93
+ };
94
+ /**
95
+ * The license and its owner as Freemius reports them, read with the vendor credentials for
96
+ * `productId`. Credentials come from the CMS settings (hydrated here) or the environment.
97
+ */
98
+ export declare function retrieveFreemiusLicenseRecords(productId: string, licenseId: string): Promise<FreemiusLicenseRecords>;
86
99
  /**
87
100
  * Look the license up with the vendor credentials for `productId` and return its key
88
101
  * when `evaluateFreemiusLicenseClaim` accepts the claim.
@@ -44,49 +44,64 @@ function c(e) {
44
44
  reason: "product_mismatch"
45
45
  };
46
46
  }
47
- async function l(r, a) {
47
+ async function l(r, i) {
48
48
  await e();
49
- let o = t(r.productId);
50
- if (!o.apiKey || !o.secretKey || !o.publicKey) return {
51
- error: "The license service is not configured for this product.",
49
+ let a = t(r);
50
+ if (!a.apiKey || !a.secretKey || !a.publicKey) return {
52
51
  ok: !1,
53
- reason: "not_configured",
54
- status: 503
52
+ reason: "not_configured"
55
53
  };
56
- let s = new n({
57
- apiKey: o.apiKey,
58
- productId: Number(r.productId),
59
- publicKey: o.publicKey,
60
- secretKey: o.secretKey
61
- }), l = null, u = null;
54
+ let o = new n({
55
+ apiKey: a.apiKey,
56
+ productId: Number(r),
57
+ publicKey: a.publicKey,
58
+ secretKey: a.secretKey
59
+ });
62
60
  try {
63
- l = await s.api.license.retrieve(r.licenseId), l?.user_id !== null && l?.user_id !== void 0 && (u = await s.api.user.retrieve(String(l.user_id)));
61
+ let e = await o.api.license.retrieve(i), t = null;
62
+ return e?.user_id !== null && e?.user_id !== void 0 && (t = await o.api.user.retrieve(String(e.user_id))), {
63
+ license: e,
64
+ ok: !0,
65
+ user: t
66
+ };
64
67
  } catch (e) {
65
- return console.error("[Freemius License Claim] Freemius lookup failed:", e), {
66
- error: "Freemius could not be reached to verify the license.",
68
+ return console.error("[Freemius License] Freemius lookup failed:", e), {
67
69
  ok: !1,
68
- reason: "upstream_error",
69
- status: 502
70
+ reason: "upstream_error"
70
71
  };
71
72
  }
72
- let d = c({
73
- license: l,
74
- maxAgeMinutes: a?.maxAgeMinutes,
75
- now: a?.now,
76
- request: r,
77
- user: u
73
+ }
74
+ async function u(e, t) {
75
+ let n = await l(e.productId, e.licenseId);
76
+ if (!n.ok) return n.reason === "not_configured" ? {
77
+ error: "The license service is not configured for this product.",
78
+ ok: !1,
79
+ reason: "not_configured",
80
+ status: 503
81
+ } : {
82
+ error: "Freemius could not be reached to verify the license.",
83
+ ok: !1,
84
+ reason: "upstream_error",
85
+ status: 502
86
+ };
87
+ let { license: r, user: a } = n, o = c({
88
+ license: r,
89
+ maxAgeMinutes: t?.maxAgeMinutes,
90
+ now: t?.now,
91
+ request: e,
92
+ user: a
78
93
  });
79
- return d.ok ? {
80
- expiration: l?.expiration ?? null,
81
- licenseKey: String(l?.secret_key),
94
+ return o.ok ? {
95
+ expiration: r?.expiration ?? null,
96
+ licenseKey: String(r?.secret_key),
82
97
  ok: !0,
83
- planId: l?.plan_id !== null && l?.plan_id !== void 0 ? String(l.plan_id) : null
98
+ planId: r?.plan_id !== null && r?.plan_id !== void 0 ? String(r.plan_id) : null
84
99
  } : {
85
100
  error: i,
86
101
  ok: !1,
87
- reason: d.reason,
102
+ reason: o.reason,
88
103
  status: 403
89
104
  };
90
105
  }
91
106
  //#endregion
92
- export { r as FREEMIUS_LICENSE_CLAIM_MAX_AGE_MINUTES, i as FREEMIUS_LICENSE_CLAIM_REFUSED_MESSAGE, l as claimFreemiusLicenseKey, c as evaluateFreemiusLicenseClaim, a as parseFreemiusTimestamp };
107
+ export { r as FREEMIUS_LICENSE_CLAIM_MAX_AGE_MINUTES, i as FREEMIUS_LICENSE_CLAIM_REFUSED_MESSAGE, u as claimFreemiusLicenseKey, c as evaluateFreemiusLicenseClaim, a as parseFreemiusTimestamp, l as retrieveFreemiusLicenseRecords };
@@ -1 +1 @@
1
- const e=require("./payment-config.cjs"),t=require("./providers/freemius.cjs");let n=require("@freemius/sdk");async function r(e,r){if(!e)return null;let i=t.resolveFreemiusCheckoutCredentials(e);return!i.apiKey||!i.secretKey||!i.publicKey?null:new n.Freemius({productId:Number(e),apiKey:i.apiKey,secretKey:i.secretKey,publicKey:i.publicKey}).api.license.retrieve(r)}async function i(t){let{data:n,error:i}=await t.client.from(`orders`).select(`id, provider, freemius_product_id, freemius_license_id, freemius_trial_ends_at`).eq(`id`,t.orderId).maybeSingle();if(i||!n||n.provider!==`freemius`||!n.freemius_license_id)return null;let a=null;try{await e.hydrateFreemiusEnvFromDb(),a=await r(n.freemius_product_id,String(n.freemius_license_id))}catch(e){console.error(`[Freemius License] Failed to retrieve license key:`,e)}return{licenseId:String(n.freemius_license_id),licenseKey:a?.secret_key??null,planId:a?.plan_id==null?null:String(a.plan_id),expiration:a?.expiration??null,trialEndsAt:n.freemius_trial_ends_at??null,isCancelled:!!a?.is_cancelled}}exports.getFreemiusOrderLicense=i;
1
+ const e=require("./payment-config.cjs"),t=require("./providers/freemius.cjs"),n=require("./freemius-license-claim.cjs");let r=require("@freemius/sdk");async function i(e,n){if(!e)return null;let i=t.resolveFreemiusCheckoutCredentials(e);return!i.apiKey||!i.secretKey||!i.publicKey?null:new r.Freemius({productId:Number(e),apiKey:i.apiKey,secretKey:i.secretKey,publicKey:i.publicKey}).api.license.retrieve(n)}async function a(t){let{data:r,error:a}=await t.client.from(`orders`).select(`id, provider, created_at, freemius_product_id, freemius_license_id, freemius_trial_ends_at`).eq(`id`,t.orderId).maybeSingle();if(a||!r||r.provider!==`freemius`||!r.freemius_license_id)return null;let o=null;try{await e.hydrateFreemiusEnvFromDb(),o=await i(r.freemius_product_id,String(r.freemius_license_id))}catch(e){console.error(`[Freemius License] Failed to retrieve license key:`,e)}let s=r.created_at?Date.parse(r.created_at):NaN,c=n.parseFreemiusTimestamp(o?.created),l=!!o&&String(o?.plugin_id??``)===String(r.freemius_product_id??``)&&Number.isFinite(s)&&c!==null&&c>=s-3e5;return o&&!l&&console.warn(`[Freemius License] Not revealing license ${r.freemius_license_id} on order ${r.id}: product or creation time does not match the order`),{licenseId:String(r.freemius_license_id),licenseKey:l?o?.secret_key??null:null,planId:o?.plan_id==null?null:String(o.plan_id),expiration:o?.expiration??null,trialEndsAt:r.freemius_trial_ends_at??null,isCancelled:!!o?.is_cancelled}}exports.getFreemiusOrderLicense=a;
@@ -1,34 +1,36 @@
1
1
  import { hydrateFreemiusEnvFromDb as e } from "./payment-config.es.js";
2
2
  import { resolveFreemiusCheckoutCredentials as t } from "./providers/freemius.es.js";
3
- import { Freemius as n } from "@freemius/sdk";
3
+ import { parseFreemiusTimestamp as n } from "./freemius-license-claim.es.js";
4
+ import { Freemius as r } from "@freemius/sdk";
4
5
  //#region src/lib/freemius-license.ts
5
- async function r(e, r) {
6
+ async function i(e, n) {
6
7
  if (!e) return null;
7
8
  let i = t(e);
8
- return !i.apiKey || !i.secretKey || !i.publicKey ? null : new n({
9
+ return !i.apiKey || !i.secretKey || !i.publicKey ? null : new r({
9
10
  productId: Number(e),
10
11
  apiKey: i.apiKey,
11
12
  secretKey: i.secretKey,
12
13
  publicKey: i.publicKey
13
- }).api.license.retrieve(r);
14
+ }).api.license.retrieve(n);
14
15
  }
15
- async function i(t) {
16
- let { data: n, error: i } = await t.client.from("orders").select("id, provider, freemius_product_id, freemius_license_id, freemius_trial_ends_at").eq("id", t.orderId).maybeSingle();
17
- if (i || !n || n.provider !== "freemius" || !n.freemius_license_id) return null;
18
- let a = null;
16
+ async function a(t) {
17
+ let { data: r, error: a } = await t.client.from("orders").select("id, provider, created_at, freemius_product_id, freemius_license_id, freemius_trial_ends_at").eq("id", t.orderId).maybeSingle();
18
+ if (a || !r || r.provider !== "freemius" || !r.freemius_license_id) return null;
19
+ let o = null;
19
20
  try {
20
- await e(), a = await r(n.freemius_product_id, String(n.freemius_license_id));
21
+ await e(), o = await i(r.freemius_product_id, String(r.freemius_license_id));
21
22
  } catch (e) {
22
23
  console.error("[Freemius License] Failed to retrieve license key:", e);
23
24
  }
24
- return {
25
- licenseId: String(n.freemius_license_id),
26
- licenseKey: a?.secret_key ?? null,
27
- planId: a?.plan_id == null ? null : String(a.plan_id),
28
- expiration: a?.expiration ?? null,
29
- trialEndsAt: n.freemius_trial_ends_at ?? null,
30
- isCancelled: !!a?.is_cancelled
25
+ let s = r.created_at ? Date.parse(r.created_at) : NaN, c = n(o?.created), l = !!o && String(o?.plugin_id ?? "") === String(r.freemius_product_id ?? "") && Number.isFinite(s) && c !== null && c >= s - 3e5;
26
+ return o && !l && console.warn(`[Freemius License] Not revealing license ${r.freemius_license_id} on order ${r.id}: product or creation time does not match the order`), {
27
+ licenseId: String(r.freemius_license_id),
28
+ licenseKey: l ? o?.secret_key ?? null : null,
29
+ planId: o?.plan_id == null ? null : String(o.plan_id),
30
+ expiration: o?.expiration ?? null,
31
+ trialEndsAt: r.freemius_trial_ends_at ?? null,
32
+ isCancelled: !!o?.is_cancelled
31
33
  };
32
34
  }
33
35
  //#endregion
34
- export { i as getFreemiusOrderLicense };
36
+ export { a as getFreemiusOrderLicense };
@@ -1 +1 @@
1
- const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./providers/freemius.cjs"),n=require("./order-inventory.cjs"),r=require("./invoice-server.cjs");let i=require("@supabase/supabase-js"),a=require("crypto");a=e.__toESM(a,1);let o=require("@freemius/sdk");function s(e){return e==null||e===``?null:String(e)}function c(e){let t=s(e);if(!t)return null;let n=t.includes(`T`)?t:t.replace(` `,`T`)+`Z`,r=new Date(n);return Number.isNaN(r.getTime())?t:r.toISOString()}function l(e){if(e==null||e===``)return null;let t=Number(e);return Number.isFinite(t)?t:null}function u(...e){return e.some(e=>{let t=l(e);return t!==null&&t>0})}function d(e){return e===`pending`||e===`trial`}function f(e){return[`license.cancelled`,`license.deleted`,`license.expired`,`subscription.cancelled`,`subscription.renewal.failed.last`,`trial.cancelled`,`trial.expired`].includes(e||``)}function p(e,t){return e===`license.extended`&&(t?.is_renewal===!0||t?.is_renewal===1||t?.is_renewal===`1`||t?.is_renewal===`true`)}function m(e){let t=e.objects?.payment??e.data?.payment??e.data;return e.type===`payment.created`&&u(t?.gross,t?.total_gross,t?.amount,t?.initial_amount)}function h(e){let t=e?.purchase??null,n=e?.trial??null;return{freemius_product_id:s(t?.plugin_id)??s(t?.product_id)??s(t?.productId)??s(n?.plugin_id)??s(n?.product_id)??s(n?.productId),freemius_plan_id:s(t?.plan_id)??s(t?.planId),freemius_license_id:s(t?.license_id)??s(t?.licenseId)??s(n?.license_id)??s(n?.licenseId),freemius_subscription_id:s(t?.subscription_id)??s(t?.subscriptionId)??s(n?.subscription_id)??s(n?.subscriptionId),freemius_trial_id:s(n?.id),freemius_user_id:s(t?.user_id)??s(t?.userId)??s(n?.user_id)??s(n?.userId)??s(e?.user?.id),freemius_trial_ends_at:c(n?.trial_ends_at)??c(n?.trialEndsAt)??c(t?.trial_ends)??c(t?.trialEnds)}}function g(e,t=`pending`){let n=e?.purchase??null,r=e?.trial??null;return t===`paid`?`paid`:r&&(r.canceled_at||r.canceledAt)&&d(t)?`cancelled`:r?`trial`:n?(n.canceled_at||n.canceledAt)&&d(t)?`cancelled`:u(n.initial_amount,n.initialAmount,n.gross,n.total_gross,n.totalGross)?`paid`:n.trial_ends||n.trialEnds||n.subscription_id||n.subscriptionId?`trial`:t:t}function _(e){let{event:t,currentStatus:n,purchaseData:r}=e;return n===`paid`&&f(t.type)?`paid`:f(t.type)?d(n)?`cancelled`:n:m(t)||p(t.type,t.data)||r&&u(r.initialAmount,r.initial_amount,r.gross,r.totalGross,r.total_gross)?`paid`:r?.canceled===!0&&d(n)?`cancelled`:n===`pending`&&(r?.trialEndsAt||r?.trial_ends_at||r?.trialEnds||r?.trial_ends)||(r?.subscriptionId||r?.subscription_id||t.type===`subscription.created`||t.type===`license.created`)&&n===`pending`?`trial`:n}function v(e,...t){let n=t.filter(e=>!!e);return e===`paid`||n.includes(`paid`)?`paid`:n.includes(`cancelled`)?`cancelled`:n.includes(`trial`)?`trial`:n.includes(`shipped`)?`shipped`:n.includes(`refunded`)?`refunded`:e}function y(e,t){let n={freemius_last_event_type:t,freemius_last_synced_at:new Date().toISOString()};for(let[t,r]of Object.entries(e))r!=null&&r!==``&&(n[t]=r);return n}function b(){let e=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,t=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!t)throw Error(`Missing Supabase Service Role environment variables`);return(0,i.createClient)(e,t,{auth:{autoRefreshToken:!1,persistSession:!1}})}async function x(e,t){let{data:n,error:r}=await e.from(`orders`).select(`id, status, provider, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at`).eq(`id`,t).single();if(r||!n)throw Error(r?.message||`Order not found`);return n}async function S(e,t){let{data:n,error:r}=await e.from(`orders`).select(`id, status, provider, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at`).eq(`freemius_license_id`,t).order(`created_at`,{ascending:!1}).limit(1).maybeSingle();if(r)throw Error(r.message);return n??null}async function C(e){let t=y(e.metadata,e.eventType),i=e.order.status,a=i===`paid`&&e.nextStatus!==`paid`?`paid`:e.nextStatus;a!==i&&(t.status=a);let{error:o}=await e.client.from(`orders`).update(t).eq(`id`,e.order.id);if(o)throw Error(o.message);return a===`paid`&&i!==`paid`&&(await r.assignInvoiceMetadata({orderId:e.order.id,client:e.client}),await n.applyOrderInventoryDeduction(e.client,e.order.id)),a}async function w(e){let t=e.client??b(),n=await x(t,e.orderId);if(n.provider!==`freemius`)return{success:!1,error:`Only Freemius orders can be synced from Freemius checkout`};let r=h(e.checkoutResponse),i=null;if(r.freemius_license_id)try{i=await D(r.freemius_product_id??n.freemius_product_id,r.freemius_license_id)}catch(e){console.error(`[Freemius Checkout Sync] Failed to retrieve purchase data:`,e)}let a={type:`checkout.purchaseCompleted`,data:{license_id:r.freemius_license_id},objects:{}},o={...r,...E(a,i)},s=g(e.checkoutResponse,n.status),c=i?_({event:a,currentStatus:n.status,purchaseData:i}):null,l=s===`paid`?n.status:s,u=await C({client:t,order:n,nextStatus:v(n.status,l,c),metadata:o,eventType:`checkout.purchaseCompleted`});return{success:!0,orderId:n.id,status:u,metadata:o}}function T(e){return s(e.data?.license_id)??s(e.objects?.license?.id)??s(e.objects?.subscription?.license_id)??s(e.objects?.payment?.license_id)??s(e.data?.payment?.license_id)}function E(e,t){let n=e.objects?.license,r=e.objects?.subscription,i=e.objects?.trial,a=e.objects?.payment??e.data?.payment;return{freemius_product_id:s(t?.productId)??s(t?.product_id)??s(n?.plugin_id)??s(r?.plugin_id)??s(a?.plugin_id),freemius_plan_id:s(t?.planId)??s(t?.plan_id)??s(n?.plan_id),freemius_license_id:s(t?.licenseId)??s(t?.license_id)??T(e),freemius_subscription_id:s(t?.subscriptionId)??s(t?.subscription_id)??s(r?.id)??s(e.data?.subscription_id),freemius_trial_id:s(i?.id)??s(e.data?.trial_id),freemius_user_id:s(t?.userId)??s(t?.user_id)??s(e.objects?.user?.id),freemius_trial_ends_at:c(i?.trial_ends_at)??c(i?.trial_ends)??c(n?.trial_ends)??c(t?.trialEndsAt)??c(t?.trial_ends_at)}}async function D(e,n){if(!e)return null;let r=t.resolveFreemiusCheckoutCredentials(e);return!r.apiKey||!r.secretKey||!r.publicKey?null:new o.Freemius({productId:Number(e),apiKey:r.apiKey,secretKey:r.secretKey,publicKey:r.publicKey}).purchase.retrievePurchaseData(n)}async function O(e){let t=e.client??b(),n=T(e.event);if(!n)return{success:!0,ignored:!0,reason:`missing_license_id`,type:e.event.type};let r=await S(t,n);if(!r)return{success:!0,ignored:!0,reason:`unknown_license_id`,licenseId:n,type:e.event.type};let i=null;try{i=await D(r.freemius_product_id??e.event.objects?.license?.plugin_id,n)}catch(e){console.error(`[Freemius Sync] Failed to retrieve purchase data:`,e)}let a=E(e.event,i),o=await C({client:t,order:r,nextStatus:_({event:e.event,currentStatus:r.status,purchaseData:i}),metadata:a,eventType:e.event.type??null});return{success:!0,orderId:r.id,status:o,type:e.event.type}}function k(){let e=[t.readFreemiusEnvValue(`FREEMIUS_SECRET_KEY`),t.readFreemiusEnvValue(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`),...Object.values(t.parseFreemiusCheckoutCredentialsMap()??{}).map(e=>e.secretKey??null)];return Array.from(new Set(e.filter(e=>!!e)))}function A(e,t){return t?k().some(n=>{let r=a.default.createHmac(`sha256`,n).update(e).digest(`hex`);try{return a.default.timingSafeEqual(Buffer.from(r,`hex`),Buffer.from(t,`hex`))}catch{return!1}}):!1}exports.extractFreemiusCheckoutMetadata=h,exports.getFreemiusWebhookSecretCandidates=k,exports.resolveFreemiusStatusFromCheckoutResponse=g,exports.resolveFreemiusStatusFromWebhookEvent=_,exports.syncFreemiusCheckoutOrder=w,exports.syncFreemiusOrderFromWebhookEvent=O,exports.verifyFreemiusWebhookSignature=A;
1
+ const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("./providers/freemius.cjs"),n=require("./order-inventory.cjs"),r=require("./invoice-server.cjs"),i=require("./freemius-license-claim.cjs");require("server-only");let a=require("@supabase/supabase-js"),o=require("crypto");o=e.__toESM(o,1);let s=require("@freemius/sdk");function c(e){return e==null||e===``?null:String(e)}function l(e){let t=c(e);if(!t)return null;let n=t.includes(`T`)?t:t.replace(` `,`T`)+`Z`,r=new Date(n);return Number.isNaN(r.getTime())?t:r.toISOString()}function u(e){if(e==null||e===``)return null;let t=Number(e);return Number.isFinite(t)?t:null}function d(...e){return e.some(e=>{let t=u(e);return t!==null&&t>0})}function f(e){return e===`pending`||e===`trial`}function p(e){return[`license.cancelled`,`license.deleted`,`license.expired`,`subscription.cancelled`,`subscription.renewal.failed.last`,`trial.cancelled`,`trial.expired`].includes(e||``)}function m(e,t){return e===`license.extended`&&(t?.is_renewal===!0||t?.is_renewal===1||t?.is_renewal===`1`||t?.is_renewal===`true`)}function h(e){let t=e.objects?.payment??e.data?.payment??e.data;return e.type===`payment.created`&&d(t?.gross,t?.total_gross,t?.amount,t?.initial_amount)}function g(e){let t=e?.purchase??null,n=e?.trial??null;return{freemius_product_id:c(t?.plugin_id)??c(t?.product_id)??c(t?.productId)??c(n?.plugin_id)??c(n?.product_id)??c(n?.productId),freemius_plan_id:c(t?.plan_id)??c(t?.planId),freemius_license_id:c(t?.license_id)??c(t?.licenseId)??c(n?.license_id)??c(n?.licenseId),freemius_subscription_id:c(t?.subscription_id)??c(t?.subscriptionId)??c(n?.subscription_id)??c(n?.subscriptionId),freemius_trial_id:c(n?.id),freemius_user_id:c(t?.user_id)??c(t?.userId)??c(n?.user_id)??c(n?.userId)??c(e?.user?.id),freemius_trial_ends_at:l(n?.trial_ends_at)??l(n?.trialEndsAt)??l(t?.trial_ends)??l(t?.trialEnds)}}function _(e,t=`pending`){let n=e?.purchase??null,r=e?.trial??null;return t===`paid`?`paid`:r&&(r.canceled_at||r.canceledAt)&&f(t)?`cancelled`:r?`trial`:n?(n.canceled_at||n.canceledAt)&&f(t)?`cancelled`:d(n.initial_amount,n.initialAmount,n.gross,n.total_gross,n.totalGross)?`paid`:n.trial_ends||n.trialEnds||n.subscription_id||n.subscriptionId?`trial`:t:t}function v(e){let{event:t,currentStatus:n,purchaseData:r}=e;return n===`paid`&&p(t.type)?`paid`:p(t.type)?f(n)?`cancelled`:n:h(t)||m(t.type,t.data)||r&&d(r.initialAmount,r.initial_amount,r.gross,r.totalGross,r.total_gross)?`paid`:r?.canceled===!0&&f(n)?`cancelled`:n===`pending`&&(r?.trialEndsAt||r?.trial_ends_at||r?.trialEnds||r?.trial_ends)||(r?.subscriptionId||r?.subscription_id||t.type===`subscription.created`||t.type===`license.created`)&&n===`pending`?`trial`:n}function y(e,...t){let n=t.filter(e=>!!e);return e===`paid`||n.includes(`paid`)?`paid`:n.includes(`cancelled`)?`cancelled`:n.includes(`trial`)?`trial`:n.includes(`shipped`)?`shipped`:n.includes(`refunded`)?`refunded`:e}function b(e,t){let n={freemius_last_event_type:t,freemius_last_synced_at:new Date().toISOString()};for(let[t,r]of Object.entries(e))r!=null&&r!==``&&(n[t]=r);return n}function x(){let e=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,t=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!t)throw Error(`Missing Supabase Service Role environment variables`);return(0,a.createClient)(e,t,{auth:{autoRefreshToken:!1,persistSession:!1}})}async function S(e,t){let{data:n,error:r}=await e.from(`orders`).select(`id, status, provider, created_at, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at`).eq(`id`,t).single();if(r||!n)throw Error(r?.message||`Order not found`);return n}async function C(e,t){let{data:n,error:r}=await e.from(`orders`).select(`id, status, provider, created_at, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at`).eq(`freemius_license_id`,t).order(`created_at`,{ascending:!1}).limit(1).maybeSingle();if(r)throw Error(r.message);return n??null}async function w(e){let t=b(e.metadata,e.eventType),i=e.order.status,a=i===`paid`&&e.nextStatus!==`paid`?`paid`:e.nextStatus;a!==i&&(t.status=a);let{error:o}=await e.client.from(`orders`).update(t).eq(`id`,e.order.id);if(o)throw Error(o.message);return a===`paid`&&i!==`paid`&&(await r.assignInvoiceMetadata({orderId:e.order.id,client:e.client}),await n.applyOrderInventoryDeduction(e.client,e.order.id)),a}var T=3e5,E=`This checkout could not be verified with Freemius. Your license key is in your purchase email.`;function D(e){let t=c(e.licenseId),n=c(e.order.freemius_product_id);if(!t)return{ok:!1,reason:`no_license_in_callback`};if(!n)return{ok:!1,reason:`missing_order_product`};let r=c(e.order.freemius_license_id);if(r&&r!==t)return{ok:!1,reason:`order_has_other_license`};if(e.linkedToOtherOrder)return{ok:!1,reason:`license_linked_to_other_order`};let a=i.evaluateFreemiusLicenseClaim({license:e.license,now:e.now,request:{email:e.callbackEmail??``,kind:`purchase`,licenseId:t,productId:n,userId:c(e.callbackUserId)??``},user:e.user});if(!a.ok)return a;let o=e.order.created_at?Date.parse(e.order.created_at):NaN,s=i.parseFreemiusTimestamp(e.license?.created);return!Number.isFinite(o)||s===null||s<o-T?{ok:!1,reason:`license_predates_order`}:{ok:!0}}async function O(e,t,n){let{data:r,error:i}=await e.from(`orders`).select(`id`).eq(`freemius_license_id`,t).neq(`id`,n).limit(1);if(i)throw Error(i.message);return Array.isArray(r)&&r.length>0}async function k(e){let t=e.client??x(),n=await S(t,e.orderId);if(n.provider!==`freemius`)return{success:!1,error:`Only Freemius orders can be synced from Freemius checkout`};let r=g(e.checkoutResponse),a=r.freemius_license_id??null,o=c(n.freemius_product_id),s=!!a&&c(n.freemius_license_id)===a,l=null;if(!s){let s;if(!a||!o)s=D({callbackEmail:null,callbackUserId:null,license:null,licenseId:a,linkedToOtherOrder:!1,order:n,user:null});else{let c=await(e.retrieveLicense??i.retrieveFreemiusLicenseRecords)(o,a);if(!c.ok)return console.error(`[Freemius Checkout Sync] Could not verify license ${a} for order ${n.id}: ${c.reason}`),{success:!1,error:E};s=D({callbackEmail:e.checkoutResponse?.user?.email??null,callbackUserId:r.freemius_user_id??null,license:c.license,licenseId:a,linkedToOtherOrder:await O(t,a,n.id),now:e.now,order:n,user:c.user}),l=c.license}if(!s.ok)return console.warn(`[Freemius Checkout Sync] Refused license ${a??`(none)`} for order ${n.id}: ${s.reason}`),{success:!1,error:E}}let u={...r,freemius_product_id:o,freemius_plan_id:c(l?.plan_id)??c(n.freemius_plan_id)??null,freemius_license_id:a,freemius_user_id:c(l?.user_id)??c(n.freemius_user_id)??null},d=null;if(a)try{d=await M(o,a)}catch(e){console.error(`[Freemius Checkout Sync] Failed to retrieve purchase data:`,e)}let f={type:`checkout.purchaseCompleted`,data:{license_id:r.freemius_license_id},objects:{}},p={...u,...j(f,d),freemius_product_id:o},m=_(e.checkoutResponse,n.status),h=d?v({event:f,currentStatus:n.status,purchaseData:d}):null,b=m===`paid`?n.status:m,C=await w({client:t,order:n,nextStatus:y(n.status,b,h),metadata:p,eventType:`checkout.purchaseCompleted`});return{success:!0,orderId:n.id,status:C,metadata:p}}function A(e){return c(e.data?.license_id)??c(e.objects?.license?.id)??c(e.objects?.subscription?.license_id)??c(e.objects?.payment?.license_id)??c(e.data?.payment?.license_id)}function j(e,t){let n=e.objects?.license,r=e.objects?.subscription,i=e.objects?.trial,a=e.objects?.payment??e.data?.payment;return{freemius_product_id:c(t?.productId)??c(t?.product_id)??c(n?.plugin_id)??c(r?.plugin_id)??c(a?.plugin_id),freemius_plan_id:c(t?.planId)??c(t?.plan_id)??c(n?.plan_id),freemius_license_id:c(t?.licenseId)??c(t?.license_id)??A(e),freemius_subscription_id:c(t?.subscriptionId)??c(t?.subscription_id)??c(r?.id)??c(e.data?.subscription_id),freemius_trial_id:c(i?.id)??c(e.data?.trial_id),freemius_user_id:c(t?.userId)??c(t?.user_id)??c(e.objects?.user?.id),freemius_trial_ends_at:l(i?.trial_ends_at)??l(i?.trial_ends)??l(n?.trial_ends)??l(t?.trialEndsAt)??l(t?.trial_ends_at)}}async function M(e,n){if(!e)return null;let r=t.resolveFreemiusCheckoutCredentials(e);return!r.apiKey||!r.secretKey||!r.publicKey?null:new s.Freemius({productId:Number(e),apiKey:r.apiKey,secretKey:r.secretKey,publicKey:r.publicKey}).purchase.retrievePurchaseData(n)}async function N(e){let t=e.client??x(),n=A(e.event);if(!n)return{success:!0,ignored:!0,reason:`missing_license_id`,type:e.event.type};let r=await C(t,n);if(!r)return{success:!0,ignored:!0,reason:`unknown_license_id`,licenseId:n,type:e.event.type};let i=null;try{i=await M(r.freemius_product_id??e.event.objects?.license?.plugin_id,n)}catch(e){console.error(`[Freemius Sync] Failed to retrieve purchase data:`,e)}let a=j(e.event,i),o=await w({client:t,order:r,nextStatus:v({event:e.event,currentStatus:r.status,purchaseData:i}),metadata:a,eventType:e.event.type??null});return{success:!0,orderId:r.id,status:o,type:e.event.type}}function P(){let e=[t.readFreemiusEnvValue(`FREEMIUS_SECRET_KEY`),t.readFreemiusEnvValue(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`),...Object.values(t.parseFreemiusCheckoutCredentialsMap()??{}).map(e=>e.secretKey??null)];return Array.from(new Set(e.filter(e=>!!e)))}function F(e,t){return t?P().some(n=>{let r=o.default.createHmac(`sha256`,n).update(e).digest(`hex`);try{return o.default.timingSafeEqual(Buffer.from(r,`hex`),Buffer.from(t,`hex`))}catch{return!1}}):!1}exports.FREEMIUS_CHECKOUT_SYNC_REFUSED_MESSAGE=E,exports.evaluateFreemiusCheckoutLicense=D,exports.extractFreemiusCheckoutMetadata=g,exports.getFreemiusWebhookSecretCandidates=P,exports.resolveFreemiusStatusFromCheckoutResponse=_,exports.resolveFreemiusStatusFromWebhookEvent=v,exports.syncFreemiusCheckoutOrder=k,exports.syncFreemiusOrderFromWebhookEvent=N,exports.verifyFreemiusWebhookSignature=F;