11import { CheckoutPopupParams } from '@freemius/checkout' ;
22import { FSId } from '../api/types' ;
33import { idToString } from '../api/parser' ;
4- import { Checkout } from '../checkout/Checkout' ;
4+ import { Checkout , CheckoutLicenseAuthorization } from '../checkout/Checkout' ;
55import { CheckoutBuilderOptions } from '../contracts/checkout' ;
66import { PurchaseService } from './PurchaseService' ;
77import { PricingService } from './PricingService' ;
88import { CheckoutRequestProcessor } from '../checkout/CheckoutRequestProcessor' ;
99import { RedirectProcessor } from '../checkout/RedirectProcessor' ;
10+ import { createHash } from 'crypto' ;
11+ import { ApiService } from './ApiService' ;
1012
1113export class CheckoutService {
1214 public readonly request : CheckoutRequestProcessor ;
1315
1416 constructor (
17+ private readonly api : ApiService ,
1518 private readonly productId : FSId ,
1619 private readonly publicKey : string ,
1720 private readonly secretKey : string ,
@@ -54,7 +57,17 @@ export class CheckoutService {
5457 * @example
5558 */
5659 async create ( options : CheckoutBuilderOptions = { } ) : Promise < Checkout > {
57- const { user, isSandbox = false , withRecommendation = true , title, image, planId, quota, trial } = options ;
60+ const {
61+ user,
62+ isSandbox = false ,
63+ withRecommendation = true ,
64+ title,
65+ image,
66+ planId,
67+ quota,
68+ trial,
69+ licenseId,
70+ } = options ;
5871
5972 const builder = new Checkout ( idToString ( this . productId ) , this . publicKey , this . secretKey ) ;
6073
@@ -67,7 +80,7 @@ export class CheckoutService {
6780 }
6881
6982 if ( isSandbox ) {
70- builder . setSandbox ( ) ;
83+ builder . setSandbox ( await this . getSandboxParams ( ) ) ;
7184 }
7285
7386 if ( title ) {
@@ -90,6 +103,11 @@ export class CheckoutService {
90103 builder . setTrial ( trial ) ;
91104 }
92105
106+ if ( licenseId ) {
107+ const authorization = await this . getLicenseUpgradeParams ( licenseId ) ;
108+ builder . setLicenseAuthorization ( authorization ) ;
109+ }
110+
93111 return builder ;
94112 }
95113
@@ -99,12 +117,34 @@ export class CheckoutService {
99117 * This shouldn't be used in production, but is useful for testing purposes.
100118 *
101119 * @note This is intentionally set as `async` because we would use the API in the future to generate more fine grained sandbox params (for example for a specific email address only).
102- *
103- * @todo - This has a duplication with the `inSandbox` method in the builder. Consider refactoring to avoid this duplication.
104- * Also think about whether we should make the builder's `inSandbox` method async as well.
105120 */
106121 async getSandboxParams ( ) : Promise < NonNullable < CheckoutPopupParams [ 'sandbox' ] > > {
107- return Checkout . createSandboxToken ( idToString ( this . productId ) , this . secretKey , this . publicKey ) ;
122+ const productId = idToString ( this . productId ) ;
123+ const timestamp = Math . floor ( Date . now ( ) / 1000 ) . toString ( ) ;
124+ const token = `${ timestamp } ${ productId } ${ this . secretKey } ${ this . publicKey } checkout` ;
125+
126+ return {
127+ ctx : timestamp ,
128+ token : createHash ( 'md5' ) . update ( token ) . digest ( 'hex' ) ,
129+ } ;
130+ }
131+
132+ /**
133+ * Retrieves the license upgrade authorization for a given license ID.
134+ *
135+ * This is used to authorize a license upgrade during the checkout process. Useful when creating upgrade links for existing users.
136+ */
137+ async getLicenseUpgradeParams ( licenseId : FSId ) : Promise < CheckoutLicenseAuthorization > {
138+ const auth = await this . api . license . retrieveCheckoutUpgradeAuthorization ( licenseId ) ;
139+
140+ if ( ! auth ) {
141+ throw new Error ( 'Failed to retrieve license upgrade authorization' ) ;
142+ }
143+
144+ return {
145+ licenseId,
146+ authorization : auth ,
147+ } ;
108148 }
109149
110150 /**
0 commit comments