@freemius/sdk 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["defaultPagingOptions: PagingOptions","client: FsApiClient","secretKey: string","publicKey: string","crypto","options: Omit<CheckoutPopupParams, 'plugin_id'> & CheckoutPopupArbitraryParams","productId: string","publicKey?: string","secretKey?: string","productId: FSId","publicKey: string","secretKey: string","api: ApiService","checkout: CheckoutService","portalPayments: PortalPayment[]","checkoutOptions: CheckoutOptions","billingData: PortalData","subscriptionData: PortalSubscription","planTitles: Record<string, string>","pricing: Record<string, PricingEntity>","api: ApiService","secretKey: string","onError: (error: unknown) => void","evt: EventEntity","secretKey: string","chunks: Buffer[]"],"sources":["../src/contracts/types.ts","../src/api/parser.ts","../src/api/client.ts","../src/api/ApiBase.ts","../src/api/License.ts","../src/api/Product.ts","../src/api/Subscription.ts","../src/api/User.ts","../src/services/ApiService.ts","../src/utils/ops.ts","../src/models/CheckoutBuilder.ts","../src/models/CheckoutRedirectInfo.ts","../src/services/CheckoutService.ts","../src/services/CustomerPortalService.ts","../src/models/PurchaseInfo.ts","../src/services/PurchaseService.ts","../src/webhook/WebhookListener.ts","../src/services/WebhookService.ts","../src/Freemius.ts"],"sourcesContent":["/**\n * This file holds all generic types used across the SDK, not specific to any contract.\n */\nexport enum BILLING_CYCLE {\n MONTHLY = 'monthly',\n YEARLY = 'yearly',\n ONEOFF = 'oneoff',\n}\n\nexport interface PagingOptions {\n count?: number;\n offset?: number;\n}\n\nexport type ApiEntitiesFilter<T> = Omit<NonNullable<T>, 'count' | 'offset'>;\n\nexport enum CURRENCY {\n USD = 'USD',\n EUR = 'EUR',\n GBP = 'GBP',\n}\n\nexport type PaymentMethod = 'card' | 'paypal' | 'ideal';\n","import { BillingCycleApiEnum, CurrencyApiEnum, FSId } from './types';\nimport { BILLING_CYCLE, CURRENCY, PaymentMethod } from '../contracts/types';\n\nexport function idToNumber(id: FSId): number {\n if (typeof id === 'number') {\n return id;\n } else if (typeof id === 'bigint') {\n return Number(id);\n } else if (typeof id === 'string') {\n const parsed = Number.parseInt(id, 10);\n\n if (Number.isNaN(parsed)) {\n throw new Error(`Invalid FSId: ${id}`);\n }\n\n return parsed;\n } else {\n throw new Error(`Unsupported FSId type: ${typeof id}`);\n }\n}\n\nexport function idToString(id: FSId): string {\n if (typeof id === 'string') {\n return id;\n } else if (typeof id === 'number' || typeof id === 'bigint') {\n return String(id);\n } else {\n throw new Error(`Unsupported FSId type: ${typeof id}`);\n }\n}\n\nexport function isIdsEqual(id1: FSId, id2: FSId): boolean {\n return idToString(id1) === idToString(id2);\n}\n\nexport function parseBillingCycle(cycle?: BillingCycleApiEnum): BILLING_CYCLE {\n const billingCycle = Number.parseInt(cycle?.toString() ?? '', 10);\n\n if (billingCycle === 1) {\n return BILLING_CYCLE.MONTHLY;\n }\n\n if (billingCycle === 12) {\n return BILLING_CYCLE.YEARLY;\n }\n\n return BILLING_CYCLE.ONEOFF;\n}\n\nexport function parseNumber(value: unknown): number | null {\n if (typeof value === 'number') {\n return value;\n } else if (typeof value === 'string') {\n const parsed = Number.parseFloat(value);\n return Number.isNaN(parsed) ? null : parsed;\n } else {\n return null;\n }\n}\n\nexport function parseDateTime(dateString?: string | null): Date | null {\n if (!dateString) {\n return null;\n }\n\n // Freemius date format is \"YYYY-MM-DD HH:mm:ss\" in UTC\n const dateParts = dateString.split(' ');\n if (dateParts.length !== 2) {\n return null;\n }\n\n const date = dateParts[0]!.split('-');\n const time = dateParts[1]!.split(':');\n if (date.length !== 3 || time.length !== 3) {\n return null;\n }\n\n const year = Number.parseInt(date[0]!);\n const month = Number.parseInt(date[1]!) - 1; // Months are zero-based\n const day = Number.parseInt(date[2]!);\n const hours = Number.parseInt(time[0]!);\n const minutes = Number.parseInt(time[1]!);\n const seconds = Number.parseInt(time[2]!);\n\n if (\n Number.isNaN(year) ||\n Number.isNaN(month) ||\n Number.isNaN(day) ||\n Number.isNaN(hours) ||\n Number.isNaN(minutes) ||\n Number.isNaN(seconds)\n ) {\n return null;\n }\n\n const utcDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));\n\n return utcDate;\n}\n\nexport function parseDate(dateString?: string | null): Date | null {\n if (!dateString) {\n return null;\n }\n\n // Freemius date format is \"YYYY-MM-DD\"\n return parseDateTime(dateString + ' 00:00:00');\n}\n\nexport function parseCurrency(currency?: CurrencyApiEnum): CURRENCY | null {\n switch (currency?.toLowerCase?.()) {\n case 'usd':\n return CURRENCY.USD;\n case 'eur':\n return CURRENCY.EUR;\n case 'gbp':\n return CURRENCY.GBP;\n default:\n return null;\n }\n}\n\nexport function parsePaymentMethod(gateway?: string | null): PaymentMethod | null {\n return gateway?.startsWith('stripe') ? 'card' : gateway?.startsWith('paypal') ? 'paypal' : null;\n}\n","import createClient from 'openapi-fetch';\nimport type { paths } from './schema';\n\nexport function createApiClient(baseUrl: string, bearerToken?: string) {\n return createClient<paths>({\n baseUrl,\n headers: {\n Authorization: bearerToken ? `Bearer ${bearerToken}` : undefined,\n },\n });\n}\n\nexport type FsApiClient = ReturnType<typeof createApiClient>;\n","import { PagingOptions } from '../contracts/types';\nimport { idToNumber } from './parser';\nimport { FsApiClient } from './client';\nimport { FSId } from './types';\n\nexport const PAGING_DEFAULT_LIMIT = 150;\nexport const PAGING_MAX_LIMIT = 300;\n\nexport const defaultPagingOptions: PagingOptions = {\n count: PAGING_DEFAULT_LIMIT,\n offset: 0,\n};\n\nexport abstract class ApiBase<EntityType, FilterType extends Record<string, unknown> = Record<string, unknown>> {\n public readonly productId: number;\n\n constructor(\n productId: FSId,\n public readonly client: FsApiClient\n ) {\n this.productId = idToNumber(productId);\n }\n\n abstract retrieve(id: FSId): Promise<EntityType | null>;\n\n abstract retrieveMany(filter?: FilterType, pagination?: PagingOptions): Promise<EntityType[]>;\n\n /**\n * Async generator that yields all entities by paginating through retrieveMany.\n * @param filter Optional filter for entities\n * @param pageSize Optional page size (default: PAGING_DEFAULT_LIMIT)\n *\n * @example\n * // Usage example:\n * for await (const entity of apiInstance.iterateAll({ status: 'active' })) {\n * console.log(entity);\n * }\n */\n async *iterateAll(\n filter?: FilterType,\n pageSize: number = PAGING_DEFAULT_LIMIT\n ): AsyncGenerator<EntityType, void, unknown> {\n let offset = 0;\n\n while (true) {\n const page = await this.retrieveMany(filter, { count: pageSize, offset });\n\n if (!page.length) {\n break;\n }\n\n for (const entity of page) {\n yield entity;\n }\n\n if (page.length < pageSize) {\n break;\n }\n\n offset += page.length;\n }\n }\n\n // Helper methods\n\n getPagingParams(paging: PagingOptions = defaultPagingOptions): { count: number; offset: number } {\n return {\n count: paging.count ?? PAGING_DEFAULT_LIMIT,\n offset: paging.offset ?? 0,\n };\n }\n\n getIdForPath(id: FSId): number {\n return idToNumber(id);\n }\n\n isGoodResponse(response: Response): boolean {\n return response.status >= 200 && response.status < 300;\n }\n}\n","import { PagingOptions } from '../contracts/types';\nimport { ApiBase } from './ApiBase';\nimport { LicenseEntity, LicenseFilterOptions, SubscriptionEntity, FSId } from './types';\n\nexport class License extends ApiBase<LicenseEntity, LicenseFilterOptions> {\n async retrieve(licenseId: FSId) {\n const licenseResponse = await this.client.GET(`/products/{product_id}/licenses/{license_id}.json`, {\n params: {\n path: {\n product_id: this.productId,\n license_id: this.getIdForPath(licenseId),\n },\n },\n });\n\n if (!this.isGoodResponse(licenseResponse.response) || !licenseResponse.data || !licenseResponse.data.id) {\n return null;\n }\n\n return licenseResponse.data;\n }\n\n async retrieveMany(filter?: LicenseFilterOptions, pagination?: PagingOptions) {\n const response = await this.client.GET(`/products/{product_id}/licenses.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n query: {\n ...this.getPagingParams(pagination),\n ...(filter ?? {}),\n },\n },\n });\n\n if (!this.isGoodResponse(response.response) || !response.data || !Array.isArray(response.data.licenses)) {\n return [];\n }\n\n return response.data.licenses;\n }\n\n async retrieveSubscription(licenseId: FSId): Promise<SubscriptionEntity | null> {\n const subscriptionResponse = await this.client.GET(\n `/products/{product_id}/licenses/{license_id}/subscription.json`,\n {\n params: {\n path: {\n product_id: this.productId,\n license_id: this.getIdForPath(licenseId),\n },\n },\n }\n );\n\n if (\n !this.isGoodResponse(subscriptionResponse.response) ||\n !subscriptionResponse.data ||\n !subscriptionResponse.data.id\n ) {\n return null;\n }\n\n return subscriptionResponse.data;\n }\n\n async retrieveCheckoutUpgradeAuthorization(licenseId: FSId): Promise<string | null> {\n const response = await this.client.POST(`/products/{product_id}/licenses/{license_id}/checkout/link.json`, {\n params: {\n path: {\n product_id: this.productId,\n license_id: this.getIdForPath(licenseId),\n },\n },\n body: {\n is_payment_method_update: true,\n },\n });\n\n if (!this.isGoodResponse(response.response) || !response.data || !response.data.settings) {\n return null;\n }\n\n return response.data.settings.authorization as string;\n }\n}\n","import { ApiBase } from './ApiBase';\nimport { ProductEntity, PricingTableData } from './types';\n\nexport class Product extends ApiBase<ProductEntity, never> {\n async retrieve(): Promise<ProductEntity | null> {\n const response = await this.client.GET(`/products/{product_id}.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data) {\n return null;\n }\n\n return response.data;\n }\n\n async retrieveMany(): Promise<ProductEntity[]> {\n throw new Error('retrieveMany is not supported for Product API');\n }\n\n async retrievePricingData(): Promise<PricingTableData | null> {\n const response = await this.client.GET(`/products/{product_id}/pricing.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data) {\n return null;\n }\n\n return response.data;\n }\n}\n","import { PagingOptions } from '../contracts/types';\nimport { ApiBase } from './ApiBase';\nimport { SubscriptionEntity, SubscriptionFilterOptions, FSId } from './types';\n\nexport class Subscription extends ApiBase<SubscriptionEntity, SubscriptionFilterOptions> {\n async retrieve(subscriptionId: FSId) {\n const response = await this.client.GET(`/products/{product_id}/subscriptions/{subscription_id}.json`, {\n params: {\n path: {\n product_id: this.productId,\n subscription_id: this.getIdForPath(subscriptionId),\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !response.data.id) {\n return null;\n }\n\n return response.data;\n }\n\n async retrieveMany(filter?: SubscriptionFilterOptions, pagination?: PagingOptions) {\n const response = await this.client.GET(`/products/{product_id}/subscriptions.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n query: {\n ...this.getPagingParams(pagination),\n ...(filter ?? {}),\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !Array.isArray(response.data.subscriptions)) {\n return [];\n }\n\n return response.data.subscriptions;\n }\n}\n","import { PagingOptions } from '../contracts/types';\nimport { ApiBase } from './ApiBase';\nimport {\n LicenseEntity,\n PaymentEntity,\n SubscriptionEntity,\n UserBillingEntity,\n UserEntity,\n UserFilterOptions,\n FSId,\n UserSubscriptionFilterOptions,\n UserLicenseFilterOptions,\n UserPaymentFilterOptions,\n} from './types';\n\nconst USER_FIELDS = 'email,first,last,picture,is_verified,id,created,updated,is_marketing_allowed';\n\nexport class User extends ApiBase<UserEntity, UserFilterOptions> {\n async retrieve(userId: FSId) {\n const userResponse = await this.client.GET(`/products/{product_id}/users/{user_id}.json`, {\n params: {\n path: {\n product_id: this.productId,\n user_id: this.getIdForPath(userId),\n },\n query: {\n fields: USER_FIELDS,\n },\n },\n });\n\n if (userResponse.response.status !== 200 || !userResponse.data || !userResponse.data.id) {\n return null;\n }\n\n return userResponse.data;\n }\n\n async retrieveMany(filter?: UserFilterOptions, pagination?: PagingOptions) {\n const response = await this.client.GET(`/products/{product_id}/users.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n query: {\n ...this.getPagingParams(pagination),\n ...(filter ?? {}),\n fields: USER_FIELDS,\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !Array.isArray(response.data.users)) {\n return [];\n }\n\n return response.data.users;\n }\n\n async retrieveByEmail(email: string): Promise<UserEntity | null> {\n const response = await this.client.GET(`/products/{product_id}/users.json`, {\n params: {\n path: {\n product_id: this.productId,\n },\n query: {\n email,\n },\n },\n });\n\n if (!this.isGoodResponse(response.response) || !Array.isArray(response.data?.users)) {\n return null;\n }\n\n return response.data.users?.[0] ?? null;\n }\n\n async retrieveBilling(userId: FSId): Promise<UserBillingEntity | null> {\n const billingResponse = await this.client.GET(`/products/{product_id}/users/{user_id}/billing.json`, {\n params: {\n path: {\n product_id: this.productId,\n user_id: this.getIdForPath(userId),\n },\n },\n });\n\n if (billingResponse.response.status !== 200 || !billingResponse.data || !billingResponse.data) {\n return null;\n }\n\n return billingResponse.data;\n }\n\n async retrieveSubscriptions(\n userId: FSId,\n filters?: UserSubscriptionFilterOptions,\n pagination?: PagingOptions\n ): Promise<SubscriptionEntity[]> {\n const response = await this.client.GET(`/products/{product_id}/users/{user_id}/subscriptions.json`, {\n params: {\n path: {\n product_id: this.productId,\n user_id: this.getIdForPath(userId),\n },\n query: {\n ...(filters ?? {}),\n ...this.getPagingParams(pagination),\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !Array.isArray(response.data.subscriptions)) {\n return [];\n }\n\n return response.data.subscriptions;\n }\n\n async retrieveLicenses(\n userId: FSId,\n filters?: UserLicenseFilterOptions,\n pagination?: PagingOptions\n ): Promise<LicenseEntity[]> {\n const response = await this.client.GET(`/products/{product_id}/users/{user_id}/licenses.json`, {\n params: {\n path: {\n product_id: this.productId,\n user_id: this.getIdForPath(userId),\n },\n query: {\n ...(filters ?? {}),\n ...this.getPagingParams(pagination),\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !Array.isArray(response.data.licenses)) {\n return [];\n }\n\n return response.data.licenses;\n }\n\n async retrievePayments(\n userId: FSId,\n filters?: UserPaymentFilterOptions,\n pagination?: PagingOptions\n ): Promise<PaymentEntity[]> {\n const response = await this.client.GET(`/products/{product_id}/users/{user_id}/payments.json`, {\n params: {\n path: {\n product_id: this.productId,\n user_id: this.getIdForPath(userId),\n },\n query: {\n ...(filters ?? {}),\n ...this.getPagingParams(pagination),\n },\n },\n });\n\n if (response.response.status !== 200 || !response.data || !Array.isArray(response.data.payments)) {\n return [];\n }\n\n return response.data.payments;\n }\n}\n","import * as crypto from 'crypto';\nimport { ApiAuthParams, FSId } from '../api/types';\nimport { FsApiClient, createApiClient } from '../api/client';\nimport { License } from '../api/License';\nimport { Product } from '../api/Product';\nimport { Subscription } from '../api/Subscription';\nimport { User } from '../api/User';\nimport { idToString } from '../api/parser';\n\nconst API_ENDPOINT_PRODUCTION = 'https://api.freemius.com/v1/';\nconst API_ENDPOINT_TEST = 'http://api.freemius-local.com:8080/v1/';\n\nexport class ApiService {\n private readonly client: FsApiClient;\n\n public readonly productId: string;\n\n public readonly user: User;\n\n public readonly license: License;\n\n public readonly product: Product;\n\n public readonly subscription: Subscription;\n\n public readonly baseUrl: string;\n\n constructor(\n productId: FSId,\n apiKey: string,\n private readonly secretKey: string,\n private readonly publicKey: string\n ) {\n const isTestServer = process.env.FS__INTERNAL__IS_DEVELOPMENT_MODE === 'true';\n this.baseUrl = isTestServer ? API_ENDPOINT_TEST : API_ENDPOINT_PRODUCTION;\n\n this.client = createApiClient(this.baseUrl, apiKey);\n this.productId = idToString(productId);\n\n this.user = new User(this.productId, this.client);\n this.license = new License(this.productId, this.client);\n this.product = new Product(this.productId, this.client);\n this.subscription = new Subscription(this.productId, this.client);\n }\n\n /**\n * Low level API client for direct access to the Freemius API.\n * Use this for advanced use cases where you need to make custom API calls.\n *\n * For regular operations, prefer using the provided services like `User`, `Subscription`, `License` etc.\n */\n get __unstable_ApiClient(): FsApiClient {\n return this.client;\n }\n\n public createUrl(path: string): string {\n // Trim leading slashes to avoid double slashes in the URL\n path = path.replace(/^\\/+/, '');\n\n return `${this.baseUrl}products/${this.productId}/${path}`;\n }\n\n /**\n * Generate signed URL for the given full URL\n */\n public getSignedUrl(fullUrl: string): string {\n const url = new URL(fullUrl);\n const resourcePath = url.pathname;\n\n const auth = this.generateAuthorizationParams(resourcePath);\n\n // Build query parameters\n url.searchParams.set('auth_date', auth.date);\n url.searchParams.set('authorization', auth.authorization);\n\n return url.toString();\n }\n\n /**\n * Generate authorization parameters for signing\n */\n public generateAuthorizationParams(\n resourcePath: string,\n method: 'POST' | 'PUT' | 'GET' | 'DELETE' = 'GET',\n jsonEncodedParams: string = '',\n contentType: string = ''\n ): ApiAuthParams {\n const eol = '\\n';\n let contentMd5 = '';\n const date = this.toDateTimeString(new Date());\n\n if (['POST', 'PUT'].includes(method) && jsonEncodedParams) {\n contentMd5 = crypto.createHash('md5').update(jsonEncodedParams).digest('hex');\n }\n\n const stringToSign = [method, contentMd5, contentType, date, resourcePath].join(eol);\n\n // If secret and public keys are identical, it means that\n // the signature uses public key hash encoding.\n const authType = this.secretKey !== this.publicKey ? 'FS' : 'FSP';\n\n const signature = crypto.createHmac('sha256', this.secretKey).update(stringToSign).digest('hex');\n const base64 = this.base64UrlEncode(signature);\n\n return {\n date,\n authorization: `${authType} ${this.productId}:${this.publicKey}:${base64}`,\n };\n }\n\n /**\n * Base64 encoding that doesn't need to be urlencode()ed.\n * Exactly the same as base64_encode except it uses\n * - instead of +\n * _ instead of /\n */\n private base64UrlEncode(input: string): string {\n return Buffer.from(input, 'utf8').toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, ''); // Remove padding\n }\n\n private toDateTimeString(date: Date): string {\n // Format date as \"YYYY-MM-DD HH:mm:ss\"\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // Months are zero-based\n const day = String(date.getUTCDate()).padStart(2, '0');\n const hours = String(date.getUTCHours()).padStart(2, '0');\n const minutes = String(date.getUTCMinutes()).padStart(2, '0');\n const seconds = String(date.getUTCSeconds()).padStart(2, '0');\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n }\n}\n","export function splitName(name: string): { firstName: string; lastName: string } {\n const parts = name.split(' ');\n\n return {\n firstName: parts[0] ?? '',\n lastName: parts.slice(1).join(' ') ?? '',\n };\n}\n","import {\n CheckoutOptions,\n CheckoutPopupParams,\n convertCheckoutOptionsToQueryParams,\n CheckoutPopupArbitraryParams,\n buildFreemiusQueryFromOptions,\n} from '@freemius/checkout';\nimport { createHash } from 'crypto';\nimport { splitName } from '../utils/ops';\n\nexport type CheckoutBuilderUserOptions =\n | { email: string; firstName?: string; lastName?: string; name?: string }\n | null\n | undefined;\n\n/**\n * A builder class for constructing checkout parameters. This class provides a fluent\n * API to create Checkout parameters for a product with various configurations.\n *\n *\n *\n * Every method returns a new instance of the builder with the updated options,\n * allowing for method chaining. The final `toOptions()` method returns the constructed\n * `CheckoutOptions` object. So the class itself is immutable and does not modify the original instance.\n */\nexport class CheckoutBuilder {\n constructor(\n private readonly options: Omit<CheckoutPopupParams, 'plugin_id'> & CheckoutPopupArbitraryParams,\n private readonly productId: string,\n private readonly publicKey?: string,\n private readonly secretKey?: string\n ) {}\n\n /**\n * Enables sandbox mode for testing purposes.\n *\n * @returns A new builder instance with sandbox configuration\n */\n inSandbox(): CheckoutBuilder {\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const token = `${timestamp}${this.productId}${this.secretKey}${this.publicKey}checkout`;\n\n return new CheckoutBuilder(\n {\n ...this.options,\n sandbox: {\n ctx: timestamp,\n token: createHash('md5').update(token).digest('hex'),\n },\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Sets user information for the checkout session.\n *\n * @param user User object with email and optional name fields. The shape matches the session from `better-auth` or next-auth packages. Also handles `null` or `undefined` gracefully.\n * @param readonly If true, the user information will be read-only in the checkout session.\n *\n * @returns A new builder instance with user configuration\n */\n withUser(user: CheckoutBuilderUserOptions, readonly: boolean = true): CheckoutBuilder {\n if (!user) {\n return this;\n }\n\n let firstName = user.firstName ?? '';\n let lastName = user.lastName ?? '';\n\n if (user.name) {\n const { firstName: fn, lastName: ln } = splitName(user.name);\n firstName = fn;\n lastName = ln;\n }\n\n return new CheckoutBuilder(\n {\n ...this.options,\n user_email: user.email,\n user_first_name: firstName,\n user_last_name: lastName,\n readonly_user: readonly,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Applies recommended UI settings for better user experience.\n * This includes fullscreen mode, upsells, refund badge, and reviews display.\n *\n * @returns A new builder instance with recommended UI settings\n */\n withRecommendation(): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n fullscreen: true,\n show_refund_badge: true,\n show_reviews: true,\n locale: 'auto',\n currency: 'auto',\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Sets the plan ID for the checkout.\n *\n * @param planId The plan ID to purchase\n * @returns A new builder instance with plan ID set\n */\n withPlan(planId: string | number): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n plan_id: planId.toString(),\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Sets the number of licenses to purchase.\n *\n * @param count Number of licenses\n * @returns A new builder instance with license count set\n */\n withQuota(count: number): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n licenses: count,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n withPricing(pricingId: string | number): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n pricing_id: pricingId.toString(),\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n withTitle(title: string): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n title,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Sets a coupon code for the checkout.\n *\n * @param coupon The coupon code to apply\n * @param hideUI Whether to hide the coupon input field from users\n * @returns A new builder instance with coupon configuration\n */\n withCoupon(options: { code: string; hideUI?: boolean }): CheckoutBuilder {\n const { code: coupon, hideUI = false } = options;\n\n const newOptions = { ...this.options, hide_coupon: hideUI };\n if (coupon !== undefined) {\n newOptions.coupon = coupon;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Enables trial mode for the checkout.\n *\n * @param mode Trial type - true/false for plan default, or specific 'free'/'paid' mode\n * @returns A new builder instance with trial configuration\n */\n inTrial(mode: 'free' | 'paid' | boolean = true): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n trial: mode,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Configures the visual layout and appearance of the checkout.\n *\n * @param options Appearance configuration options\n * @returns A new builder instance with appearance configuration\n */\n withAppearance(options: {\n layout?: 'vertical' | 'horizontal' | null;\n formPosition?: 'left' | 'right';\n fullscreen?: boolean;\n modalTitle?: string;\n id?: string; // Custom body ID for CSS targeting\n }): CheckoutBuilder {\n const newOptions = { ...this.options };\n\n if (options.layout !== undefined) {\n newOptions.layout = options.layout;\n }\n if (options.formPosition !== undefined) {\n newOptions.form_position = options.formPosition;\n }\n if (options.fullscreen !== undefined) {\n newOptions.fullscreen = options.fullscreen;\n }\n if (options.modalTitle !== undefined) {\n newOptions.modal_title = options.modalTitle;\n }\n\n if (options.id !== undefined) {\n newOptions.id = options.id;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Configures discount display settings.\n *\n * @param options Discount configuration options\n * @returns A new builder instance with discount configuration\n */\n withDiscounts(options: {\n annual?: boolean;\n multisite?: boolean | 'auto';\n bundle?: boolean | 'maximize';\n showMonthlySwitch?: boolean;\n }): CheckoutBuilder {\n const newOptions = { ...this.options };\n\n if (options.annual !== undefined) {\n newOptions.annual_discount = options.annual;\n }\n if (options.multisite !== undefined) {\n newOptions.multisite_discount = options.multisite;\n }\n if (options.bundle !== undefined) {\n newOptions.bundle_discount = options.bundle;\n }\n if (options.showMonthlySwitch !== undefined) {\n newOptions.show_monthly_switch = options.showMonthlySwitch;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Configures billing cycle selector interface.\n *\n * @param selector Type of billing cycle selector to show\n * @param defaultCycle Default billing cycle to select\n * @returns A new builder instance with billing cycle configuration\n */\n withBillingCycle(\n defaultCycle: 'monthly' | 'annual' | 'lifetime',\n selector?: 'list' | 'responsive_list' | 'dropdown'\n ): CheckoutBuilder {\n const newOptions = { ...this.options };\n\n if (selector !== undefined) {\n newOptions.billing_cycle_selector = selector;\n }\n if (defaultCycle !== undefined) {\n newOptions.billing_cycle = defaultCycle;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Sets the language/locale for the checkout.\n *\n * @param locale Language setting - 'auto', 'auto-beta', or specific locale like 'en_US'\n * @returns A new builder instance with locale configuration\n */\n withLanguage(locale: 'auto' | 'auto-beta' | string = 'auto'): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n language: locale,\n locale: locale,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Configures review and badge display settings.\n *\n * @param options Review and badge configuration\n * @returns A new builder instance with reviews and badges configuration\n */\n withReviewsAndBadges(options: {\n showReviews?: boolean;\n reviewId?: number;\n showRefundBadge?: boolean;\n refundPolicyPosition?: 'below_form' | 'below_breakdown' | 'dynamic';\n }): CheckoutBuilder {\n const newOptions = { ...this.options };\n\n if (options.showReviews !== undefined) {\n newOptions.show_reviews = options.showReviews;\n }\n if (options.reviewId !== undefined) {\n newOptions.review_id = options.reviewId;\n }\n if (options.showRefundBadge !== undefined) {\n newOptions.show_refund_badge = options.showRefundBadge;\n }\n if (options.refundPolicyPosition !== undefined) {\n newOptions.refund_policy_position = options.refundPolicyPosition;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Enhanced currency configuration.\n *\n * @param currency Primary currency or 'auto' for automatic detection\n * @param defaultCurrency Default currency when using 'auto'\n * @param showInlineSelector Whether to show inline currency selector\n * @returns A new builder instance with currency configuration\n */\n withCurrency(\n currency: 'usd' | 'eur' | 'gbp' | 'auto',\n defaultCurrency: 'usd' | 'eur' | 'gbp' = 'usd',\n showInlineSelector: boolean = true\n ): CheckoutBuilder {\n const options = {\n ...this.options,\n show_inline_currency_selector: showInlineSelector,\n default_currency: defaultCurrency,\n };\n\n // Only set currency if it's not 'auto'\n if (currency !== 'auto') {\n options.currency = currency;\n }\n\n return new CheckoutBuilder(options, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Configures navigation and cancel behavior.\n *\n * @param cancelUrl URL for back button when in page mode\n * @param cancelIcon Custom cancel icon URL\n * @returns A new builder instance with navigation configuration\n */\n withNavigation(cancelUrl?: string, cancelIcon?: string): CheckoutBuilder {\n const newOptions = { ...this.options };\n\n if (cancelUrl !== undefined) {\n newOptions.cancel_url = cancelUrl;\n }\n if (cancelIcon !== undefined) {\n newOptions.cancel_icon = cancelIcon;\n }\n\n return new CheckoutBuilder(newOptions, this.productId, this.publicKey, this.secretKey);\n }\n\n /**\n * Associates purchases with an affiliate account.\n *\n * @param userId Affiliate user ID\n * @returns A new builder instance with affiliate configuration\n */\n withAffiliate(userId: number): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n affiliate_user_id: userId,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Sets a custom image/icon for the checkout.\n *\n * @param imageUrl Secure HTTPS URL to the image\n * @returns A new builder instance with custom image\n */\n withImage(imageUrl: string): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n image: imageUrl,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Configures the checkout for license renewal.\n *\n * @param licenseKey The license key to renew\n * @returns A new builder instance configured for renewal\n */\n forRenewal(licenseKey: string): CheckoutBuilder {\n return new CheckoutBuilder(\n {\n ...this.options,\n license_key: licenseKey,\n },\n this.productId,\n this.publicKey,\n this.secretKey\n );\n }\n\n /**\n * Builds and returns the final checkout options to be used with the `@freemius/checkout` package.\n *\n * @returns The constructed CheckoutOptions object\n */\n toOptions(\n additionalOptions?: Omit<CheckoutPopupParams, 'plugin_id'> & CheckoutPopupArbitraryParams\n ): CheckoutOptions {\n return { ...this.options, ...additionalOptions, product_id: this.productId };\n }\n\n toLink(): string {\n const checkoutOptions = convertCheckoutOptionsToQueryParams(this.options);\n\n const queryParams = buildFreemiusQueryFromOptions(checkoutOptions);\n\n const url = new URL(`https://checkout.freemius.com/product/${this.productId}/`);\n url.search = queryParams;\n\n return url.href;\n }\n}\n","import { idToString, parseBillingCycle, parseCurrency, parseDateTime, parseNumber } from '../api/parser';\nimport { BillingCycleApiEnum, CurrencyApiEnum, FSId } from '../api/types';\nimport { CheckoutRedirectData } from '../contracts/checkout';\nimport { BILLING_CYCLE, CURRENCY } from '../contracts/types';\n\nexport class CheckoutRedirectInfo implements CheckoutRedirectData {\n user_id: string;\n plan_id: string;\n email: string;\n pricing_id: string;\n currency: CURRENCY;\n license_id: string;\n expiration: Date | null;\n quota: number | null;\n action: 'payment_method_update' | 'license_update' | null;\n amount: number;\n tax: number;\n type: 'subscription' | 'one-off';\n subscription_id: string | null;\n billing_cycle: BILLING_CYCLE | null;\n payment_id: string | null;\n\n // Add these to the constructor to initialize the new members\n constructor(data: Record<string, unknown>) {\n this.user_id = idToString(data.user_id as FSId);\n this.plan_id = idToString(data.plan_id as FSId);\n this.email = data.email as string;\n this.pricing_id = idToString(data.pricing_id as FSId);\n this.currency = data.currency ? parseCurrency(data.currency as CurrencyApiEnum)! : CURRENCY.USD;\n this.license_id = idToString(data.license_id as FSId);\n this.expiration = data.expiration ? parseDateTime(data.expiration as string) : null;\n this.quota = data.quota ? parseNumber(data.quota) : null;\n this.action = data.action ? (data.action as 'payment_method_update' | 'license_update') : null;\n this.amount = parseNumber(data.amount as string)!;\n this.tax = parseNumber(data.tax as string)!;\n this.type = data.type === 'subscription' ? 'subscription' : 'one-off';\n this.subscription_id = data.subscription_id ? idToString(data.subscription_id as string) : null;\n this.billing_cycle = data.billing_cycle ? parseBillingCycle(data.billing_cycle as BillingCycleApiEnum) : null;\n this.payment_id = data.payment_id ? idToString(data.payment_id as string) : null;\n }\n\n isSubscription(): boolean {\n return this.type === 'subscription';\n }\n\n toData(): CheckoutRedirectData {\n return {\n user_id: this.user_id,\n plan_id: this.plan_id,\n email: this.email,\n pricing_id: this.pricing_id,\n currency: this.currency,\n license_id: this.license_id,\n expiration: this.expiration,\n quota: this.quota,\n action: this.action,\n amount: this.amount,\n tax: this.tax,\n type: this.type,\n subscription_id: this.subscription_id,\n billing_cycle: this.billing_cycle,\n payment_id: this.payment_id,\n };\n }\n}\n","import { CheckoutPopupParams, CheckoutOptions } from '@freemius/checkout';\nimport { FSId } from '../api/types';\nimport { idToString } from '../api/parser';\nimport { CheckoutBuilder, CheckoutBuilderUserOptions } from '../models/CheckoutBuilder';\nimport { createHash, createHmac, timingSafeEqual } from 'crypto';\nimport { CheckoutRedirectInfo } from '../models/CheckoutRedirectInfo';\n\nexport class CheckoutService {\n constructor(\n private readonly productId: FSId,\n private readonly publicKey: string,\n private readonly secretKey: string\n ) {}\n\n /**\n * Use this to build a Checkout for your product.\n * You can build a Checkout link or options for the popup.\n *\n * @param withRecommendation If true, the checkout will include a recommendation for the user.\n *\n * @return A new instance of CheckoutBuilder with the product ID and public key.\n *\n * @example\n * Basic usage:\n * ```typescript\n * const options = freemius.checkout.params()\n * .withUser(session?.user)\n * .inSandbox()\n * .withRecommendation()\n * .toOptions(); // Or .toLink() for a hosted checkout link\n * ```\n *\n * @example\n * Advanced configuration:\n * ```typescript\n * const checkoutOptions = freemius.checkout.params()\n * .withUser(user, true)\n * .withPlan('1234')\n * .withQuota(5)\n * .withCurrency('eur')\n * .withCoupon({\n * code: 'DISCOUNT2023',\n * hideUI: false\n * })\n * .inTrial('paid')\n * .withAppearance({\n * layout: 'horizontal',\n * formPosition: 'left',\n * fullscreen: true,\n * modalTitle: 'Upgrade Now'\n * })\n * .withDiscounts({\n * annual: true,\n * multisite: 'auto',\n * bundle: 'maximize',\n * showMonthlySwitch: true\n * })\n * .withReviewsAndBadges({\n * showReviews: true,\n * showRefundBadge: true,\n * refundPolicyPosition: 'below_form'\n * })\n * .withBillingCycle('dropdown', 'annual')\n * .withLocale('en_US')\n * .withAffiliate(12345)\n * .inSandbox()\n * .toOptions();\n * ```\n */\n create(withRecommendation: boolean = true): CheckoutBuilder {\n const productId = idToString(this.productId);\n\n const builder = new CheckoutBuilder({}, productId, this.publicKey, this.secretKey);\n\n return withRecommendation ? builder.withRecommendation() : builder;\n }\n\n /**\n * Convenience method to create checkout options for a specific user with or without sandbox mode.\n *\n * Useful for generating recommended checkout options for SaaS.\n */\n createUserOptions(user: CheckoutBuilderUserOptions, isSandbox: boolean = false): CheckoutOptions {\n let builder = this.create().withUser(user);\n\n if (isSandbox) {\n builder = builder.inSandbox();\n }\n\n return builder.toOptions();\n }\n\n /**\n * Convenience method to create a checkout link for a specific user with or without sandbox mode.\n *\n * Useful for generating recommended checkout links for SaaS.\n */\n createUserLink(user: CheckoutBuilderUserOptions, isSandbox: boolean = false): string {\n let builder = this.create().withUser(user);\n\n if (isSandbox) {\n builder = builder.inSandbox();\n }\n\n return builder.toLink();\n }\n\n /**\n * Retrieves the sandbox parameters for the checkout.\n *\n * This shouldn't be used in production, but is useful for testing purposes.\n *\n * @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).\n *\n * @todo - This has a duplication with the `inSandbox` method in the builder. Consider refactoring to avoid this duplication.\n * Also think about whether we should make the builder's `inSandbox` method async as well.\n */\n async getSandboxParams(): Promise<NonNullable<CheckoutPopupParams['sandbox']>> {\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const token = `${timestamp}${this.productId}${this.secretKey}${this.publicKey}checkout`;\n\n return {\n ctx: timestamp,\n token: createHash('md5').update(token).digest('hex'),\n };\n }\n\n /**\n * Processes the redirect from Freemius Checkout.\n *\n * This method verifies the signature in the URL and returns a CheckoutRedirectInfo object if successful.\n *\n * For nextjs like applications, make sure to replace the URL from the `Request` object with the right hostname to take care of the proxy.\n *\n * For example, if you have put the nextjs application behind nginx proxy (or ngrok during local development), then nextjs will still see the `request.url` as `https://localhost:3000/...`.\n * In this case, you should replace it with the actual URL of your application, like `https://xyz.ngrok-free.app/...`.\n *\n * @example\n * ```ts\n * export async function GET(request: Request) {\n * // Replace the URL with the actual hostname of your application\n * // This is important for the signature verification to work correctly.\n * const data = await freemius.checkout.processRedirect(\n * request.url.replace('https://localhost:3000', 'https://xyz.ngrok-free.app')\n * );\n * }\n * ```\n */\n async processRedirect(currentUrl: string): Promise<CheckoutRedirectInfo | null> {\n const url = new URL(\n currentUrl\n // Handle spaces in the URL, which may be encoded as %20 or +\n .replace(/%20/g, '+')\n );\n\n const signature = url.searchParams.get('signature');\n\n if (!signature) {\n return null;\n }\n\n const cleanUrl = this.getCleanUrl(url.href);\n\n // Calculate HMAC SHA256\n const calculatedSignature = createHmac('sha256', this.secretKey).update(cleanUrl).digest('hex');\n\n // Compare signatures securely\n const result = timingSafeEqual(Buffer.from(calculatedSignature), Buffer.from(signature));\n\n if (!result) {\n return null;\n }\n\n const params = Object.fromEntries(url.searchParams.entries());\n\n if (!params.user_id || !params.plan_id || !params.pricing_id || !params.email) {\n return null;\n }\n\n return new CheckoutRedirectInfo(params);\n }\n\n // Helper to get the current absolute URL (removing \"&signature=...\" or \"?signature=...\" by string slicing)\n private getCleanUrl(url: string): string {\n const signatureParam = '&signature=';\n const signatureParamFirst = '?signature=';\n\n let signaturePos = url.indexOf(signatureParam);\n\n if (signaturePos === -1) {\n signaturePos = url.indexOf(signatureParamFirst);\n }\n\n if (signaturePos === -1) {\n // No signature param found, return as is\n return url;\n }\n\n return url.substring(0, signaturePos);\n }\n}\n","import { ApiService } from './ApiService';\nimport { PricingTableData, FSId, PricingEntity } from '../api/types';\nimport { PortalData, PortalSubscription, PortalPayment } from '../contracts/portal';\nimport {\n parseBillingCycle,\n parseNumber,\n idToString,\n parseDateTime,\n isIdsEqual,\n parseCurrency,\n parsePaymentMethod,\n} from '../api/parser';\nimport { CURRENCY } from '../contracts/types';\nimport { CheckoutService } from './CheckoutService';\nimport { CheckoutOptions } from '@freemius/checkout';\n\nexport class CustomerPortalService {\n constructor(\n private readonly api: ApiService,\n private readonly checkout: CheckoutService\n ) {}\n\n /**\n * Retrieves the customer portal data for a user, including subscriptions, billing, and payments.\n *\n * @param userId The ID of the user for whom to retrieve portal data.\n * @param primaryLicenseId Optional primary license ID to include in the portal data. If present then the `primary` field will be populated with related information which our `@freemius/saas-starter` package uses to display the primary purchase information.\n */\n async retrieveData(\n userId: FSId,\n primaryLicenseId: FSId | null = null,\n sandbox: boolean = false\n ): Promise<PortalData | null> {\n const [user, pricingData, subscriptions, payments, billing] = await Promise.all([\n this.api.user.retrieve(userId),\n this.api.product.retrievePricingData(),\n this.api.user.retrieveSubscriptions(userId),\n this.api.user.retrievePayments(userId),\n this.api.user.retrieveBilling(userId),\n ]);\n\n if (!user || !pricingData || !subscriptions) {\n return null;\n }\n\n const planTitles = this.getPlanTitleById(pricingData!);\n\n const allPricingsById = this.getPricingById(pricingData!);\n\n const portalPayments: PortalPayment[] = payments.map((payment) => ({\n ...payment,\n // @todo - Add invoice URL directly from the API by signing the URL.\n invoiceUrl: this.api.getSignedUrl(this.api.createUrl(`payments/${payment.id}/invoice.pdf`)),\n paymentMethod: parsePaymentMethod(payment.gateway)!,\n createdAt: parseDateTime(payment.created) ?? new Date(),\n planTitle: planTitles[payment.plan_id!] ?? `Plan ${payment.plan_id!}`,\n quota: allPricingsById[payment.pricing_id!]?.licenses ?? null,\n }));\n\n const checkoutOptions: CheckoutOptions = {\n product_id: this.api.productId,\n };\n\n if (sandbox) {\n checkoutOptions.sandbox = await this.checkout.getSandboxParams();\n }\n\n const billingData: PortalData = {\n user,\n checkoutOptions,\n billing,\n subscriptions: {\n primary: null,\n active: [],\n past: [],\n },\n payments: portalPayments,\n plans: pricingData.plans ?? [],\n sellingUnit: pricingData.selling_unit_label ?? {\n singular: 'Unit',\n plural: 'Units',\n },\n productId: this.api.productId,\n };\n\n subscriptions.forEach((subscription) => {\n const isActive = null === subscription.canceled_at;\n\n const subscriptionData: PortalSubscription = {\n subscriptionId: idToString(subscription.id!),\n planId: idToString(subscription.plan_id!),\n pricingId: idToString(subscription.pricing_id!),\n planTitle: planTitles[subscription.plan_id!] ?? `Plan ${subscription.plan_id!}`,\n renewalAmount: parseNumber(subscription.renewal_amount)!,\n initialAmount: parseNumber(subscription.initial_amount)!,\n billingCycle: parseBillingCycle(subscription.billing_cycle),\n isActive: isActive,\n renewalDate: parseDateTime(subscription.next_payment),\n licenseId: idToString(subscription.license_id!),\n currency: parseCurrency(subscription.currency) ?? CURRENCY.USD,\n createdAt: parseDateTime(subscription.created) ?? new Date(),\n cancelledAt: subscription.canceled_at ? parseDateTime(subscription.canceled_at) : null,\n quota: allPricingsById[subscription.pricing_id!]?.licenses ?? null,\n paymentMethod: parsePaymentMethod(subscription.gateway),\n };\n\n if (isActive) {\n billingData.subscriptions.active.push(subscriptionData);\n } else {\n billingData.subscriptions.past.push(subscriptionData);\n }\n\n if (isActive && primaryLicenseId && isIdsEqual(subscription.license_id!, primaryLicenseId)) {\n billingData.subscriptions.primary = subscriptionData;\n }\n });\n\n // Sort subscriptions by created date, most recent first\n billingData.subscriptions.active.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n billingData.subscriptions.past.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n if (!billingData.subscriptions.primary) {\n // If no primary subscription is set, use the first active or inactive subscription as primary\n billingData.subscriptions.primary =\n billingData.subscriptions.active[0] ?? billingData.subscriptions.past[0] ?? null;\n }\n\n // @todo - Right now add the checkout upgrade authorization to the primary subscription if it exists. In the future our API itself can return this data.\n if (billingData.subscriptions.primary) {\n billingData.subscriptions.primary.checkoutUpgradeAuthorization =\n await this.api.license.retrieveCheckoutUpgradeAuthorization(\n billingData.subscriptions.primary.licenseId\n );\n }\n\n return billingData;\n }\n\n /**\n * @todo - Implement this method to handle actions like get cancel coupon, cancel subscription, update billing, get upgrade auth for Checkout etc.\n */\n // async processAction(request: Request) {}\n\n private getPlanTitleById(pricingData: PricingTableData): Record<string, string> {\n const planTitles: Record<string, string> = {};\n\n pricingData.plans?.forEach((plan) => {\n planTitles[plan.id!] = plan.title ?? plan.name ?? 'Unknown Plan';\n });\n\n return planTitles;\n }\n\n private getPricingById(pricingData: PricingTableData): Record<string, PricingEntity> {\n const pricing: Record<string, PricingEntity> = {};\n\n pricingData.plans?.forEach((plan) => {\n plan.pricing?.forEach((p) => {\n pricing[p.id!] = p;\n });\n });\n\n return pricing;\n }\n}\n","import { BILLING_CYCLE, CURRENCY } from '../contracts/types';\nimport {\n parseBillingCycle,\n parseNumber,\n idToString,\n isIdsEqual,\n parseDateTime,\n parseCurrency,\n parsePaymentMethod,\n} from '../api/parser';\nimport { PurchaseData } from '../contracts/purchase';\nimport { PricingTableData, FSId, UserEntity, LicenseEntity, SubscriptionEntity } from '../api/types';\n\nexport class PurchaseInfo implements PurchaseData {\n readonly email: string;\n readonly firstName: string;\n readonly lastName: string;\n readonly userId: string;\n readonly planId: string;\n readonly pricingId: string;\n readonly licenseId: string;\n readonly expiration: Date | null;\n readonly canceled: boolean;\n readonly subscriptionId: string | null;\n readonly billingCycle: BILLING_CYCLE | null;\n readonly quota: number | null;\n readonly initialAmount: number | null;\n readonly renewalAmount: number | null;\n readonly currency: CURRENCY | null;\n readonly renewalDate: Date | null;\n readonly paymentMethod: 'card' | 'paypal' | 'ideal' | null;\n readonly created: Date;\n\n constructor(user: UserEntity, license: LicenseEntity, subscription: SubscriptionEntity | null) {\n this.email = user.email!;\n this.firstName = user.first ?? '';\n this.lastName = user.last ?? '';\n this.userId = idToString(license.user_id!);\n this.canceled = license.is_cancelled ?? false;\n this.expiration = license.expiration ? parseDateTime(license.expiration) : null;\n this.licenseId = idToString(license.id!);\n this.planId = idToString(license.plan_id!);\n this.subscriptionId = null;\n this.billingCycle = null;\n this.quota = license.quota ?? null;\n this.pricingId = idToString(license.pricing_id!);\n this.initialAmount = null;\n this.renewalAmount = null;\n this.currency = null;\n this.renewalDate = null;\n this.paymentMethod = null;\n this.created = parseDateTime(license.created) ?? new Date();\n\n if (subscription) {\n this.subscriptionId = idToString(subscription.id!);\n this.billingCycle = parseBillingCycle(subscription.billing_cycle);\n this.initialAmount = parseNumber(subscription.initial_amount);\n this.renewalAmount = parseNumber(subscription.renewal_amount);\n this.currency = parseCurrency(subscription.currency);\n this.renewalDate = subscription.next_payment ? parseDateTime(subscription.next_payment) : null;\n this.paymentMethod = parsePaymentMethod(subscription.gateway);\n }\n }\n\n isPlan(planId: FSId): boolean {\n return this.planId === idToString(planId);\n }\n\n isFromPlans(planIds: FSId[]): boolean {\n return planIds.some((planId) => this.isPlan(planId));\n }\n\n toData(): PurchaseData {\n return {\n email: this.email,\n firstName: this.firstName,\n lastName: this.lastName,\n userId: this.userId,\n planId: this.planId,\n pricingId: this.pricingId,\n licenseId: this.licenseId,\n expiration: this.expiration,\n canceled: this.canceled,\n subscriptionId: this.subscriptionId,\n billingCycle: this.billingCycle,\n quota: this.quota,\n isActive: this.isActive,\n initialAmount: this.initialAmount,\n renewalAmount: this.renewalAmount,\n currency: this.currency,\n renewalDate: this.renewalDate,\n paymentMethod: this.paymentMethod,\n created: this.created,\n };\n }\n\n get isActive(): boolean {\n if (this.canceled) {\n return false;\n }\n\n if (this.expiration && this.expiration < new Date()) {\n return false;\n }\n\n return true;\n }\n\n hasSubscription(): boolean {\n return this.subscriptionId !== null;\n }\n\n isAnnual(): boolean {\n return this.billingCycle === BILLING_CYCLE.YEARLY;\n }\n\n isMonthly(): boolean {\n return this.billingCycle === BILLING_CYCLE.MONTHLY;\n }\n\n isOneOff(): boolean {\n return this.billingCycle === BILLING_CYCLE.ONEOFF || this.billingCycle === null;\n }\n\n getPlanTitle(pricingData: PricingTableData | null): string {\n const plan = pricingData?.plans?.find((p) => isIdsEqual(p.id!, this.planId));\n\n return plan?.title ?? plan?.name ?? 'Deleted Plan';\n }\n}\n","import { FSId, SubscriptionEntity, UserEntity } from '../api/types';\nimport { PurchaseInfo } from '../models/PurchaseInfo';\nimport { PurchaseData } from '../contracts/purchase';\nimport { ApiService } from './ApiService';\nimport { PagingOptions } from '../contracts/types';\nimport { isIdsEqual } from '../api/parser';\n\nexport class PurchaseService {\n constructor(private readonly api: ApiService) {}\n\n /**\n * Retrieve purchase information from the Freemius API based on the license ID.\n *\n * The license is the primary entitlement for a purchase, and it may or may not be associated with a subscription.\n * With this method, you can retrieve detailed information about the purchase, including user details, plan, expiration, and more.\n */\n async retrievePurchase(licenseId: FSId): Promise<PurchaseInfo | null> {\n const [license, subscription] = await Promise.all([\n await this.api.license.retrieve(licenseId),\n await this.api.license.retrieveSubscription(licenseId),\n ]);\n\n if (!license) {\n return null;\n }\n\n const user = await this.api.user.retrieve(license.user_id!);\n\n if (!user) {\n return null;\n }\n\n return new PurchaseInfo(user, license, subscription);\n }\n\n /**\n * A helper method to retrieve raw purchase data instead of a full PurchaseInfo object.\n *\n * This is useful when passing data from server to client in frameworks like Next.js, where only serializable data should be sent.\n */\n async retrievePurchaseData(licenseId: FSId): Promise<PurchaseData | null> {\n const purchaseInfo = await this.retrievePurchase(licenseId);\n\n if (!purchaseInfo) {\n return null;\n }\n\n return purchaseInfo.toData();\n }\n\n /**\n * Retrieve a list of active subscriptions for a user. You can use this method to find or sync subscriptions from freemius to your system.\n */\n async retrieveSubscriptions(userId: FSId, pagination?: PagingOptions): Promise<PurchaseInfo[]> {\n const user = await this.api.user.retrieve(userId);\n\n if (!user) {\n return [];\n }\n\n const subscriptions = await this.api.user.retrieveSubscriptions(\n userId,\n {\n filter: 'active',\n },\n pagination\n );\n\n if (!subscriptions || !subscriptions.length) {\n return [];\n }\n\n // @todo - Improve rate limiting by batching requests or using a more efficient method.\n const licenseSubscriptionPromises = subscriptions.map(async (subscription) => {\n const license = await this.api.license.retrieve(subscription.license_id!);\n\n if (!license) {\n return null;\n }\n\n return new PurchaseInfo(user, license, subscription);\n });\n\n return await Promise.all(licenseSubscriptionPromises).then((results) =>\n results\n // Remove null values and sort by creation date, where the recent purchase is first.\n .filter((result): result is PurchaseInfo => result !== null)\n .sort((a, b) => b.created.getTime() - a.created.getTime())\n );\n }\n\n /**\n * Retrieve a list of purchase data for a user.\n *\n * This is a convenience method that returns the purchase data in a format suitable for client-side rendering or serialization.\n */\n async retrieveSubscriptionsData(userId: FSId, pagination?: PagingOptions): Promise<PurchaseData[]> {\n const purchaseInfos = await this.retrieveSubscriptions(userId, pagination);\n\n return purchaseInfos.map((info) => info.toData());\n }\n\n async retrieveBySubscription(\n subscription: SubscriptionEntity,\n subscriptionUser?: UserEntity\n ): Promise<PurchaseInfo | null> {\n if (!subscription.license_id) {\n return null;\n }\n\n const license = await this.api.license.retrieve(subscription.license_id);\n\n if (!license) {\n return null;\n }\n\n const user =\n subscriptionUser && isIdsEqual(subscriptionUser.id!, license.user_id!)\n ? subscriptionUser\n : await this.api.user.retrieve(license.user_id!);\n\n if (!user) {\n return null;\n }\n\n return new PurchaseInfo(user, license, subscription);\n }\n\n async retrieveActiveSubscriptionByEmail(email: string, pagination?: PagingOptions): Promise<PurchaseInfo[] | null> {\n const user = await this.api.user.retrieveByEmail(email);\n\n if (!user) {\n return null;\n }\n\n return await this.retrieveSubscriptions(user.id!, pagination);\n }\n}\n","import crypto from 'crypto';\nimport { EventHandler, FreemiusEventType, FreemiusEvent } from './events';\nimport { EventEntity } from '../api/types';\n\nexport interface NormalizedRequest {\n headers: Record<string, string | string[] | undefined> | Headers;\n rawBody: string | Buffer; // MUST be the exact raw body Freemius sent\n}\n\nexport type WebhookListenerResponse = {\n status: number;\n} & ({ success: true } | { success: false; error: string });\n\nconst SIGNATURE_HEADER = 'x-signature';\n\nexport class WebhookListener {\n private eventHandlers: Map<FreemiusEventType, Set<EventHandler<FreemiusEventType>>> = new Map();\n\n constructor(\n private readonly secretKey: string,\n private readonly onError: (error: unknown) => void = console.error\n ) {}\n\n on<T extends FreemiusEventType>(type: T, handler: EventHandler<T>): this {\n if (!this.eventHandlers.has(type)) {\n this.eventHandlers.set(type, new Set());\n }\n\n const existingHandlers = this.eventHandlers.get(type)!;\n\n existingHandlers?.add(handler as EventHandler<FreemiusEventType>);\n return this;\n }\n\n off<T extends FreemiusEventType>(type: T, handler: EventHandler<T>): this {\n const currentHandlers = this.eventHandlers.get(type);\n if (!currentHandlers) {\n return this;\n }\n\n // Set.delete() returns true if the element was in the set\n currentHandlers.delete(handler as EventHandler<FreemiusEventType>);\n\n // Remove the entire entry if no handlers remain\n if (currentHandlers.size === 0) {\n this.eventHandlers.delete(type);\n }\n\n return this;\n }\n\n onMultiple<T extends FreemiusEventType>(handlers: Partial<Record<T, EventHandler<T>>>): this {\n for (const [type, handler] of Object.entries(handlers) as [T, EventHandler<T>][]) {\n if (handler) {\n this.on(type, handler);\n }\n }\n\n return this;\n }\n\n // Remove all handlers for a specific event type\n removeAll<T extends FreemiusEventType>(type: T): this {\n this.eventHandlers.delete(type);\n return this;\n }\n\n // Get handler count for debugging\n getHandlerCount<T extends FreemiusEventType>(type: T): number {\n return this.eventHandlers.get(type)?.size ?? 0;\n }\n\n // Get total number of event types with handlers\n getEventTypeCount(): number {\n return this.eventHandlers.size;\n }\n\n // Get all registered event types\n getRegisteredEventTypes(): FreemiusEventType[] {\n return Array.from(this.eventHandlers.keys());\n }\n\n // Check if a specific event type has any handlers\n hasHandlers<T extends FreemiusEventType>(type: T): boolean {\n const handlers = this.eventHandlers.get(type);\n return handlers !== undefined && handlers.size > 0;\n }\n\n // Check if a specific handler is registered for an event type\n hasHandler<T extends FreemiusEventType>(type: T, handler: EventHandler<T>): boolean {\n const handlers = this.eventHandlers.get(type);\n return handlers ? handlers.has(handler as EventHandler<FreemiusEventType>) : false;\n }\n\n // Get all handlers for a specific event type (useful for debugging)\n getHandlers<T extends FreemiusEventType>(type: T): Set<EventHandler<FreemiusEventType>> {\n return this.eventHandlers.get(type) || new Set();\n }\n\n // Get total count of all handlers across all event types\n getTotalHandlerCount(): number {\n let total = 0;\n for (const handlers of this.eventHandlers.values()) {\n total += handlers.size;\n }\n return total;\n }\n\n /**\n * Verify hex HMAC signature against the raw body.\n */\n verifySignature(rawBody: string | Buffer, signature: string | null): boolean {\n if (!signature) {\n return false;\n }\n\n const mac = crypto.createHmac('sha256', this.secretKey).update(rawBody).digest('hex');\n\n try {\n return crypto.timingSafeEqual(Buffer.from(mac, 'hex'), Buffer.from(signature, 'hex'));\n } catch {\n return false;\n }\n }\n\n /**\n * Process a normalized request.\n * Returns an object you can map to your framework's response easily.\n */\n async process(input: NormalizedRequest): Promise<WebhookListenerResponse> {\n const sig = this.getHeader(SIGNATURE_HEADER, input.headers);\n\n if (!this.verifySignature(input.rawBody, sig)) {\n return { status: 401, success: false, error: 'Invalid signature' };\n }\n\n let evt: EventEntity;\n try {\n const parsed = JSON.parse(\n typeof input.rawBody === 'string' ? input.rawBody : input.rawBody.toString('utf8')\n );\n\n if (!parsed || typeof parsed.type !== 'string') {\n return { status: 400, success: false, error: 'Invalid payload' };\n }\n\n evt = parsed as EventEntity;\n } catch {\n return { status: 400, success: false, error: 'Malformed JSON' };\n }\n\n const eventType = evt.type as FreemiusEventType;\n const eventHandlers = this.eventHandlers.get(eventType);\n\n if (!eventHandlers || eventHandlers.size === 0) {\n // Optionally log unhandled events\n console.warn(`No handlers registered for event type: ${eventType}`);\n }\n\n try {\n // Execute handlers with proper type casting\n const promises = Array.from(eventHandlers || []).map((handler) => {\n const typedHandler = handler as EventHandler<typeof eventType>;\n const typedEvent = evt as FreemiusEvent<typeof eventType>;\n return typedHandler(typedEvent);\n });\n\n // Execute handlers in parallel for better performance\n await Promise.all(promises);\n } catch (error) {\n this.onError?.(error as Error);\n return { status: 500, success: false, error: 'Internal Server Error' };\n }\n\n return { status: 200, success: true };\n }\n\n private getHeader(name: string, headers: NormalizedRequest['headers']): string | null {\n const lname = name.toLowerCase();\n\n if (headers instanceof Headers) {\n return headers.get(lname);\n }\n\n const v = headers[lname] ?? headers[name];\n\n if (Array.isArray(v)) {\n return v[0] ?? null;\n }\n\n return (v as string | undefined) ?? null;\n }\n}\n","import { WebhookListener } from '../webhook/WebhookListener';\n\nexport class WebhookService {\n constructor(private readonly secretKey: string) {}\n\n createListener(onError?: (error: unknown) => void): WebhookListener {\n return new WebhookListener(this.secretKey, onError);\n }\n\n /**\n * WHATWG Fetch API adapter for modern JavaScript environments.\n *\n * Compatible with:\n * - Next.js App Router (route.ts files)\n * - Cloudflare Workers\n * - Deno\n * - Bun\n * - Vercel Edge Functions\n * - Any environment supporting the WHATWG Fetch API\n *\n * This method reads the request body as text and processes the webhook,\n * returning a standard Response object that can be directly returned\n * from your endpoint handler.\n *\n * @param listener - The webhook listener instance\n * @param request - The incoming Request object (WHATWG Fetch API)\n * @returns A Response object with the webhook processing result\n *\n * @example\n * ```typescript\n * // Next.js App Router (app/webhook/route.ts)\n * export async function POST(request: Request) {\n * const listener = webhookService.createListener();\n * return await webhookService.processFetch(listener, request);\n * }\n *\n * // Cloudflare Workers\n * export default {\n * async fetch(request: Request): Promise<Response> {\n * if (new URL(request.url).pathname === '/webhook') {\n * const listener = webhookService.createListener();\n * return await webhookService.processFetch(listener, request);\n * }\n * return new Response('Not Found', { status: 404 });\n * }\n * };\n * ```\n */\n async processFetch(listener: WebhookListener, request: Request): Promise<Response> {\n const rawBody = await request.text();\n const result = await listener.process({ headers: request.headers, rawBody });\n\n return new Response(JSON.stringify(result), {\n status: result.status,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n /**\n * Native Node.js HTTP server adapter.\n *\n * Reads the raw body from the request stream and writes the HTTP response directly.\n *\n * @example\n * ```typescript\n * import { createServer } from 'http';\n *\n * const server = createServer(async (req, res) => {\n * if (req.url === '/webhook') {\n * await freemius.webhook.processNodeHttp(listener, req, res);\n * }\n * });\n * ```\n */\n async processNodeHttp(\n listener: WebhookListener,\n req: import('http').IncomingMessage,\n res: import('http').ServerResponse\n ): Promise<void> {\n // Read the raw body from the request stream\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk);\n }\n\n const rawBody = Buffer.concat(chunks);\n\n const result = await listener.process({ headers: req.headers, rawBody });\n\n res.statusCode = result.status;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(result));\n }\n\n // @todo - Implement other adapters.\n\n // /**\n // * Express adapter.\n // * Route MUST use: express.raw({ type: '* / *' })\n // * Writes the HTTP response directly.\n // */\n // async fromExpress(\n // listener: WebhookListener,\n // req: import('express').Request,\n // res: import('express').Response\n // ): Promise<void> {\n // const { status, ...body } = await listener.process({ headers: req.headers as any, rawBody: req.body });\n // res.status(status).json(body);\n // }\n\n // /**\n // * Fastify adapter.\n // * Must register raw buffer parser:\n // * fastify.addContentTypeParser('* /*', { parseAs: 'buffer' }, (_req, body, done) => done(null, body))\n // * Writes the HTTP response directly.\n // */\n // async fromFastify(\n // listener: WebhookListener,\n // request: { headers: Record<string, string | string[] | undefined>; body: Buffer },\n // reply: { code: (n: number) => any; send: (payload: any) => any }\n // ): Promise<void> {\n // const { status, ...body } = await listener.process({ headers: request.headers, rawBody: request.body });\n // reply.code(status).send(body);\n // }\n}\n","import { ApiService } from './services/ApiService';\nimport { CheckoutService } from './services/CheckoutService';\nimport { CustomerPortalService } from './services/CustomerPortalService';\nimport { PurchaseService } from './services/PurchaseService';\nimport { FSId } from './api/types';\nimport { WebhookService } from './services/WebhookService';\n\nexport class Freemius {\n public readonly api: ApiService;\n\n public readonly checkout: CheckoutService;\n\n public readonly purchase: PurchaseService;\n\n public readonly customerPortal: CustomerPortalService;\n\n public readonly webhook: WebhookService;\n\n constructor(productId: FSId, apiKey: string, secretKey: string, publicKey: string) {\n this.api = new ApiService(productId, apiKey, secretKey, publicKey);\n this.checkout = new CheckoutService(productId, publicKey, secretKey);\n this.purchase = new PurchaseService(this.api);\n this.customerPortal = new CustomerPortalService(this.api, this.checkout);\n this.webhook = new WebhookService(secretKey);\n }\n}\n\nexport { PurchaseInfo } from './models/PurchaseInfo';\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@freemius/sdk",
3
+ "version": "0.0.1",
4
+ "description": "NodeJS SDK for integrating your SaaS with Freemius",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ }
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsdown",
24
+ "dev": "tsdown --watch",
25
+ "clean": "rm -rf dist",
26
+ "typecheck": "tsc --noEmit",
27
+ "test": "echo \"No tests yet\"",
28
+ "openapi:generate": "openapi-typescript https://freemius.com/help/documentation/api/openapi.yaml -o ./api/schema.d.ts",
29
+ "openapi:generate:local": "openapi-typescript http://api-doc.freemius-local.com:8080/openapi.yaml -o ./api/schema.d.ts"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+ssh://git@github.com/Freemius/freemius-js.git"
34
+ },
35
+ "keywords": [
36
+ "node.js",
37
+ "freemius",
38
+ "sdk",
39
+ "saas"
40
+ ],
41
+ "author": "Freemius Inc",
42
+ "license": "MIT",
43
+ "bugs": {
44
+ "url": "https://github.com/Freemius/freemius-node/issues"
45
+ },
46
+ "homepage": "https://github.com/Freemius/freemius-node#readme",
47
+ "dependencies": {
48
+ "openapi-fetch": "^0.14.0"
49
+ },
50
+ "peerDependencies": {
51
+ "@freemius/checkout": "*"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^24.2.0",
55
+ "tsdown": "^0.14.1",
56
+ "typescript": "^5.9.2"
57
+ }
58
+ }