UNPKG

@kirz/react-native-toolkit

Version:

Toolkit to speed up React Native development

171 lines (167 loc) 8.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InAppPurchasePlugin = void 0; var _reactNative = require("react-native"); var IAP = _interopRequireWildcard(require("react-native-iap")); var _transformProduct = require("./utils/transformProduct"); var _transformPurchase = require("./utils/transformPurchase"); var _transformSubscription = require("./utils/transformSubscription"); var _control = require("../../utils/promise/control"); var _Plugin = require("../Plugin"); var _types = require("../types"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } class InAppPurchasePlugin extends _Plugin.Plugin { // @ts-ignore // @ts-ignore // @ts-ignore constructor(options) { super(); this.options = options; _defineProperty(this, "name", 'InAppPurchasePlugin'); _defineProperty(this, "features", ['InAppPurchase']); _defineProperty(this, "initializationTimeout", 15000); _defineProperty(this, "products", void 0); _defineProperty(this, "subscriptions", void 0); _defineProperty(this, "receiptValidator", void 0); _defineProperty(this, "purchasePromise", null); } async initialize(bundle) { const iapReceiptValidator = bundle.getByFeature('IAPReceiptValidator'); if (!iapReceiptValidator) { throw new Error('No receipt validator found'); } await IAP.initConnection(); if (_reactNative.Platform.OS === 'android') { try { await IAP.flushFailedPurchasesCachedAsPendingAndroid(); } catch { // skip error } } if (_reactNative.Platform.OS === 'ios') { try { await IAP.clearTransactionIOS(); } catch { // skip error } } this.receiptValidator = iapReceiptValidator; await this.refetchProducts(); IAP.purchaseUpdatedListener(async purchase => { const productDef = this.options.products.find(x => x.productId === purchase.productId); try { var _this$purchasePromise; if (!productDef) { console.error('Unknown product: ' + purchase.productId); return; } const timestamp = new Date().valueOf(); const purchaseDate = purchase.transactionDate; if (Math.abs(purchaseDate - timestamp) > 1000 * 60 * 30) { return; } if (_reactNative.Platform.OS === 'android' && [IAP.PurchaseStateAndroid.PENDING, IAP.PurchaseStateAndroid.UNSPECIFIED_STATE].includes(purchase.purchaseStateAndroid)) { console.warn(`Skip purchase with status ${purchase.purchaseStateAndroid}`); return; } await IAP.finishTransaction({ purchase, isConsumable: productDef.type === 'consumable' }).catch(() => { // no-op }); await this.receiptValidator.handlePurchase(); (_this$purchasePromise = this.purchasePromise) === null || _this$purchasePromise === void 0 ? void 0 : _this$purchasePromise.resolve(purchase); } catch (err) { var _this$purchasePromise2; (_this$purchasePromise2 = this.purchasePromise) === null || _this$purchasePromise2 === void 0 ? void 0 : _this$purchasePromise2.reject({ isCancelled: false, message: err.message }); } }); IAP.purchaseErrorListener(async errorEvent => { var _this$purchasePromise3; (_this$purchasePromise3 = this.purchasePromise) === null || _this$purchasePromise3 === void 0 ? void 0 : _this$purchasePromise3.reject({ isCancelled: errorEvent.code === 'E_USER_CANCELLED', message: errorEvent.message }); }); } async refetchProducts() { const productSkus = this.options.products.filter(x => x.type !== 'subscription').map(x => x.productId); const subscriptionSkus = this.options.products.filter(x => x.type === 'subscription').map(x => x.productId); const [fetchedProducts, fetchedSubscriptions] = await Promise.all([productSkus.length ? IAP.getProducts({ skus: productSkus }) : Promise.resolve([]), subscriptionSkus.length ? IAP.getSubscriptions({ skus: subscriptionSkus }) : Promise.resolve([])]); const products = fetchedProducts.map(x => (0, _transformProduct.transformProduct)(x, this.options.products.find(y => y.productId === x.productId).type === 'consumable')); const subscriptions = await Promise.all(fetchedSubscriptions.map(async x => { const { trial, ...subscription } = (0, _transformSubscription.transformSubscription)(x); const isTrialAvailable = !!trial && (_reactNative.Platform.OS === 'android' || (await this.receiptValidator.isTrialAvailable(subscription.productId))); return new _types.Subscription({ ...subscription, ...(isTrialAvailable && { trial }) }); })); this.products = products.sort((a, b) => a.price - b.price); this.subscriptions = subscriptions.sort((a, b) => a.price - b.price); } async purchaseProduct(productId) { const productDef = this.options.products.find(x => x.productId === productId); if (!productDef) { throw new Error(`Unknown product "${productId}"`); } if (productDef.type === 'subscription') { // Handle android purchase request if (_reactNative.Platform.OS === 'android') { var _subscriptionOfferDet; const subscription = this.subscriptions.find(x => x.productId === productId); const offerToken = (_subscriptionOfferDet = subscription.originalData.subscriptionOfferDetails[0]) === null || _subscriptionOfferDet === void 0 ? void 0 : _subscriptionOfferDet.offerToken; const subscriptionRequest = { subscriptionOffers: [{ sku: productId, offerToken }] }; IAP.requestSubscription({ sku: productId, subscriptionOffers: subscriptionRequest.subscriptionOffers }).catch(() => { // no-op }); } else { IAP.requestSubscription({ sku: productId }).catch(() => { // no-op }); } } else { IAP.requestPurchase(_reactNative.Platform.OS === 'ios' ? { sku: productId } : { skus: [productId] }).catch(() => { // no-op }); } this.purchasePromise = new _control.ControlledPromise(); const purchase = await this.purchasePromise.wait(); return (0, _transformPurchase.transformPurchase)(purchase); } } exports.InAppPurchasePlugin = InAppPurchasePlugin; //# sourceMappingURL=InAppPurchasePlugin.js.map