export function toSensiblePayloadFormat()

in typescript/src/services/appleValidateReceipts.ts [163:287]


export function toSensiblePayloadFormat(
  response: AppleValidationServerResponse,
  receipt: string,
): AppleValidationResponse[] {
  function expiryDate(
    receiptServerInfo: AppleValidatedReceiptServerInfo,
  ): number {
    if (receiptServerInfo.expires_date_ms) {
      return Number.parseInt(receiptServerInfo.expires_date_ms);
    } else if (receiptServerInfo.expires_date) {
      return Number.parseInt(receiptServerInfo.expires_date);
    } else {
      throw new ProcessingError(
        'Receipt has no expiry, this should have been filtered by now',
        false,
      );
    }
  }

  function getReceiptInfo(): AppleValidatedReceiptServerInfo[] {
    if (response.latest_receipt_info) {
      if (Array.isArray(response.latest_receipt_info)) {
        const latestReceipt = response.latest_receipt_info;
        if (latestReceipt.length == 0) {
          console.error(
            `Invalid validation response, empty receipt info array`,
          );
          throw new ProcessingError(
            `Invalid validation response, empty receipt info array`,
          );
        }

        // only keep receipts that have an expiry date, those who don't aren't subscriptions or are pre 2011
        const filteredLatestReceipt = latestReceipt.filter(
          (receipt) => receipt.expires_date || receipt.expires_date_ms,
        );

        const deDupedReceipts = filteredLatestReceipt
          .sort((r1, r2) => expiryDate(r1) - expiryDate(r2)) // most recent last
          .reduce(
            (acc: Record<string, AppleValidatedReceiptServerInfo>, current) => {
              acc[current.original_transaction_id] = current;
              return acc;
            },
            {},
          );

        return Object.values(deDupedReceipts);
      } else {
        return [response.latest_receipt_info];
      }
    } else {
      if (response.latest_expired_receipt_info) {
        return [response.latest_expired_receipt_info];
      } else {
        // should be impossible as this will be caught by checkResponseStatus
        console.error(`No receipt info`);
        throw new ProcessingError(
          `Invalid validation response, no receipt info`,
        );
      }
    }
  }

  type PendingRenewalInfoById = Record<string, PendingRenewalInfo>;
  const pendingRenewalInfoArray = response.pending_renewal_info ?? [];
  const pendingRenewalInfoById: PendingRenewalInfoById =
    pendingRenewalInfoArray.reduce<PendingRenewalInfoById>((agg, value) => {
      agg[value.original_transaction_id] = value;
      return agg;
    }, {});

  return getReceiptInfo().map((receiptInfo) => {
    const pendingRenewalInfo: PendingRenewalInfo =
      pendingRenewalInfoById[receiptInfo.original_transaction_id];
    const autoRenewStatus = pendingRenewalInfo
      ? pendingRenewalInfo.auto_renew_status === '1'
      : response.auto_renew_status === 1;

    // bundle_id is the documented field, however it's sometimes not valued, but instead there's the field bid
    // which is valued but undocumented. Oh and also sometimes it's on the latest_receipt object, but sometimes
    // it's on the receipt object. Hopefully this covers all the corner cases? who knows!
    const bundleId =
      receiptInfo.bundle_id ??
      receiptInfo.bid ??
      response.receipt?.bundle_id ??
      response.receipt?.bid;
    if (!bundleId) {
      console.warn(
        `Unable to identify the bundle id for the original transaction id ${receiptInfo.original_transaction_id}`,
      );
    }

    const originalPurchaseDate = optionalMsToDate(
      receiptInfo.original_purchase_date_ms,
    );
    if (originalPurchaseDate === null) {
      console.error(
        `Unable to parse the original purchase date ${receiptInfo.original_purchase_date_ms}`,
      );
      throw new ProcessingError(
        `Unable to parse the original purchase date`,
        false,
      );
    }

    return {
      isRetryable: response['is-retryable'] === true,
      latestReceipt: response.latest_receipt ?? receipt,
      latestReceiptInfo: {
        bundleId: bundleId,
        autoRenewStatus: autoRenewStatus,
        cancellationDate: optionalMsToDate(receiptInfo.cancellation_date_ms),
        expiresDate: new Date(expiryDate(receiptInfo)),
        originalPurchaseDate: originalPurchaseDate,
        originalTransactionId: receiptInfo.original_transaction_id,
        productId: receiptInfo.product_id,
        trialPeriod: receiptInfo.is_trial_period === 'true',
        inIntroOfferPeriod: receiptInfo.is_in_intro_offer_period === 'true',
        appAccountToken: receiptInfo.app_account_token,
      },
      originalResponse: response,
    };
  });
}