{"version":3,"file":"request.mjs","sources":["../../../../../../lib/billing/request.ts"],"sourcesContent":["import {ConfigInterface, ConfigParams} from '../base-types';\nimport {BillingInterval} from '../types';\nimport {BillingError} from '../error';\nimport {buildEmbeddedAppUrl} from '../auth/get-embedded-app-url';\nimport {GraphqlClient, graphqlClientClass} from '../clients/admin';\nimport {hashString} from '../../runtime/crypto';\nimport {HashFormat} from '../../runtime/crypto/types';\nimport {FutureFlagOptions} from '../../future/flags';\n\nimport {\n  BillingConfigOneTimePlan,\n  BillingRequestParams,\n  BillingRequestResponse,\n  RecurringPaymentResponse,\n  RequestResponseData,\n  SinglePaymentResponse,\n  BillingConfigSubscriptionLineItemPlan,\n  RequestConfigLineItemOverrides,\n  BillingRequest,\n  APP_SUBSCRIPTION_FRAGMENT,\n} from './types';\n\nconst RECURRING_PURCHASE_MUTATION = `\n  ${APP_SUBSCRIPTION_FRAGMENT}\n  mutation AppSubscriptionCreate(\n    $name: String!\n    $returnUrl: URL!\n    $test: Boolean\n    $trialDays: Int\n    $replacementBehavior: AppSubscriptionReplacementBehavior\n    $lineItems: [AppSubscriptionLineItemInput!]!\n  ) {\n    appSubscriptionCreate(\n      name: $name\n      returnUrl: $returnUrl\n      test: $test\n      trialDays: $trialDays\n      replacementBehavior: $replacementBehavior\n      lineItems: $lineItems\n    ) {\n      appSubscription {\n        ...AppSubscriptionFragment\n      }\n      confirmationUrl\n      userErrors {\n        field\n        message\n      }\n    }\n  }\n`;\n\nconst ONE_TIME_PURCHASE_MUTATION = `\n  mutation test(\n    $name: String!\n    $price: MoneyInput!\n    $returnUrl: URL!\n    $test: Boolean\n  ) {\n    appPurchaseOneTimeCreate(\n      name: $name\n      price: $price\n      returnUrl: $returnUrl\n      test: $test\n    ) {\n      appPurchaseOneTime {\n        id\n        name\n        test\n      }\n      confirmationUrl\n      userErrors {\n        field\n        message\n      }\n    }\n  }\n`;\n\ninterface RequestInternalParams {\n  client: GraphqlClient;\n  plan: string;\n  returnUrl: string;\n  isTest: boolean;\n}\n\ninterface RequestOneTimePaymentInternalParams extends RequestInternalParams {\n  billingConfig: BillingConfigOneTimePlan;\n}\n\ninterface RequestSubscriptionParams extends RequestInternalParams {\n  billingConfig: BillingConfigSubscriptionLineItemPlan;\n}\n\nexport function request<\n  Config extends ConfigInterface<Params>,\n  Params extends ConfigParams<any, Future>,\n  Future extends FutureFlagOptions,\n>(config: Config): BillingRequest {\n  return async function <Params extends BillingRequestParams>({\n    session,\n    plan,\n    isTest = true,\n    returnUrl: returnUrlParam,\n    returnObject = false,\n    ...overrides\n  }: Params): Promise<BillingRequestResponse<Params>> {\n    if (!config.billing || !config.billing[plan]) {\n      throw new BillingError({\n        message: `Could not find plan ${plan} in billing settings`,\n        errorData: [],\n      });\n    }\n\n    const billingConfig = {\n      ...config.billing[plan],\n    };\n    const filteredOverrides = Object.fromEntries(\n      Object.entries(overrides).filter(([_key, value]) => value !== undefined),\n    );\n\n    const cleanShopName = session.shop.replace('.myshopify.com', '');\n    const embeddedAppUrl = buildEmbeddedAppUrl(config)(\n      hashString(`admin.shopify.com/store/${cleanShopName}`, HashFormat.Base64),\n    );\n\n    const appUrl = `${config.hostScheme}://${config.hostName}?shop=${session.shop}`;\n\n    // if provided a return URL, use it, otherwise use the embedded app URL or hosted app URL\n    const returnUrl =\n      returnUrlParam || (config.isEmbeddedApp ? embeddedAppUrl : appUrl);\n\n    const GraphqlClient = graphqlClientClass({config});\n    const client = new GraphqlClient({session});\n\n    function isLineItemPlan(\n      billingConfig: any,\n    ): billingConfig is BillingConfigSubscriptionLineItemPlan {\n      return 'lineItems' in billingConfig;\n    }\n\n    function isOneTimePlan(\n      billingConfig: any,\n    ): billingConfig is BillingConfigOneTimePlan {\n      return billingConfig.interval === BillingInterval.OneTime;\n    }\n\n    let data: RequestResponseData;\n    if (isLineItemPlan(billingConfig)) {\n      const mergedBillingConfigs = mergeBillingConfigs(\n        billingConfig,\n        filteredOverrides,\n      );\n      const mutationRecurringResponse = await requestSubscriptionPayment({\n        billingConfig: mergedBillingConfigs,\n        plan,\n        client,\n        returnUrl,\n        isTest,\n      });\n\n      data = mutationRecurringResponse.appSubscriptionCreate!;\n    } else if (isOneTimePlan(billingConfig)) {\n      const mutationOneTimeResponse = await requestSinglePayment({\n        billingConfig: {...billingConfig, ...filteredOverrides},\n        plan,\n        client,\n        returnUrl,\n        isTest,\n      });\n      data = mutationOneTimeResponse.appPurchaseOneTimeCreate!;\n    } else {\n      throw new BillingError({\n        message: `Invalid billing configuration for plan ${plan}. Must be either a one-time plan or a subscription plan with line items.`,\n        errorData: [],\n      });\n    }\n\n    if (data.userErrors?.length) {\n      throw new BillingError({\n        message: 'Error while billing the store',\n        errorData: data.userErrors,\n      });\n    }\n\n    if (returnObject) {\n      return data as Omit<\n        RequestResponseData,\n        'userErrors'\n      > as BillingRequestResponse<Params>;\n    } else {\n      return data.confirmationUrl as BillingRequestResponse<Params>;\n    }\n  };\n}\n\nasync function requestSubscriptionPayment({\n  billingConfig,\n  plan,\n  client,\n  returnUrl,\n  isTest,\n}: RequestSubscriptionParams): Promise<RecurringPaymentResponse> {\n  const lineItems = billingConfig.lineItems.map((item) => {\n    if (\n      item.interval === BillingInterval.Every30Days ||\n      item.interval === BillingInterval.Annual\n    ) {\n      const appRecurringPricingDetails: any = {\n        interval: item.interval,\n        price: {\n          amount: item.amount,\n          currencyCode: item.currencyCode,\n        },\n      };\n\n      if (item.discount) {\n        appRecurringPricingDetails.discount = {\n          durationLimitInIntervals: item.discount.durationLimitInIntervals,\n          value: {\n            amount: item.discount.value.amount,\n            percentage: item.discount.value.percentage,\n          },\n        };\n      }\n\n      return {\n        plan: {\n          appRecurringPricingDetails,\n        },\n      };\n    } else if (item.interval === BillingInterval.Usage) {\n      const appUsagePricingDetails = {\n        terms: item.terms,\n        cappedAmount: {\n          amount: item.amount,\n          currencyCode: item.currencyCode,\n        },\n      };\n\n      return {\n        plan: {\n          appUsagePricingDetails,\n        },\n      };\n    } else {\n      throw new BillingError({\n        message: 'Invalid interval provided',\n        errorData: [item],\n      });\n    }\n  });\n\n  const mutationResponse = await client.request<RecurringPaymentResponse>(\n    RECURRING_PURCHASE_MUTATION,\n    {\n      variables: {\n        name: plan,\n        trialDays: billingConfig.trialDays,\n        replacementBehavior: billingConfig.replacementBehavior,\n        returnUrl,\n        test: isTest,\n        lineItems,\n      },\n    },\n  );\n\n  if (mutationResponse.errors) {\n    throw new BillingError({\n      message: 'Error while billing the store',\n      errorData: mutationResponse.errors,\n    });\n  }\n\n  return mutationResponse.data!;\n}\n\nasync function requestSinglePayment({\n  billingConfig,\n  plan,\n  client,\n  returnUrl,\n  isTest,\n}: RequestOneTimePaymentInternalParams): Promise<SinglePaymentResponse> {\n  const mutationResponse = await client.request<SinglePaymentResponse>(\n    ONE_TIME_PURCHASE_MUTATION,\n    {\n      variables: {\n        name: plan,\n        returnUrl,\n        test: isTest,\n        price: {\n          amount: billingConfig.amount,\n          currencyCode: billingConfig.currencyCode,\n        },\n      },\n    },\n  );\n\n  if (mutationResponse.errors) {\n    throw new BillingError({\n      message: 'Error while billing the store',\n      errorData: mutationResponse.errors,\n    });\n  }\n\n  return mutationResponse.data!;\n}\n\nfunction mergeBillingConfigs(\n  billingConfig: BillingConfigSubscriptionLineItemPlan,\n  overrides: RequestConfigLineItemOverrides,\n): BillingConfigSubscriptionLineItemPlan {\n  const mergedConfig = {...billingConfig, ...overrides};\n  const mergedLineItems = [];\n\n  if (billingConfig.lineItems && overrides.lineItems) {\n    for (const i of billingConfig.lineItems) {\n      let found = false;\n\n      for (const j of overrides.lineItems) {\n        if (i.interval === j!.interval) {\n          mergedLineItems.push({...i, ...j});\n          found = true;\n          break;\n        }\n      }\n\n      if (!found) {\n        mergedLineItems.push(i);\n      }\n    }\n\n    mergedConfig.lineItems = mergedLineItems;\n  }\n\n  return mergedConfig as BillingConfigSubscriptionLineItemPlan;\n}\n"],"names":[],"mappings":"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"}