@revenuecat/purchases-capacitor-ui
Version:
UI components for RevenueCat Capacitor SDK
222 lines • 11 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { registerPlugin } from '@capacitor/core';
import { IOS_PAYWALL_PRESENTATION_STYLE, ANDROID_PAYWALL_PRESENTATION_STYLE, PURCHASE_LOGIC_RESULT, } from './definitions';
const nativePlugin = registerPlugin('RevenueCatUI', {
web: () => import('./web').then((m) => new m.RevenueCatUIWeb()),
});
function assertValidPresentationConfiguration(config) {
if (config === undefined) {
return;
}
if (typeof config !== 'object' || config === null) {
throw new Error(`Invalid presentationConfiguration: expected an object or undefined.`);
}
const { ios, android } = config;
const validIos = Object.values(IOS_PAYWALL_PRESENTATION_STYLE);
const validAndroid = Object.values(ANDROID_PAYWALL_PRESENTATION_STYLE);
if (ios !== undefined && !validIos.includes(ios)) {
throw new Error(`Invalid presentationConfiguration.ios "${String(ios)}". Expected one of: ${validIos.join(', ')}.`);
}
if (android !== undefined && !validAndroid.includes(android)) {
throw new Error(`Invalid presentationConfiguration.android "${String(android)}". Expected one of: ${validAndroid.join(', ')}.`);
}
}
function resolveNativePresentationOptions(config) {
if (!config) {
return {};
}
// iOS full-screen takes precedence as the flag that the native bridge understands
if (config.ios === IOS_PAYWALL_PRESENTATION_STYLE.FULL_SCREEN) {
return { useFullScreenPresentation: true };
}
return {};
}
function serializeResultForNative(result) {
if (result.result === PURCHASE_LOGIC_RESULT.ERROR && 'error' in result && result.error) {
return {
result: result.result,
error: {
code: result.error.code,
message: result.error.message,
},
};
}
return { result: result.result };
}
async function presentWithListenerSupport(nativeMethod, options, listener, purchaseLogic) {
const handles = [];
try {
// Register PaywallListener event handlers
if (listener) {
if (listener.onPurchaseStarted) {
const cb = listener.onPurchaseStarted;
handles.push(await nativePlugin.addListener('onPurchaseStarted', (data) => {
var _a;
cb({ packageBeingPurchased: (_a = data.packageBeingPurchased) !== null && _a !== void 0 ? _a : data });
}));
}
if (listener.onPurchaseCompleted) {
const cb = listener.onPurchaseCompleted;
handles.push(await nativePlugin.addListener('onPurchaseCompleted', (data) => {
cb({
customerInfo: data.customerInfo,
storeTransaction: data.storeTransaction,
});
}));
}
if (listener.onPurchaseError) {
const cb = listener.onPurchaseError;
handles.push(await nativePlugin.addListener('onPurchaseError', (data) => {
var _a;
cb({ error: (_a = data.error) !== null && _a !== void 0 ? _a : data });
}));
}
if (listener.onPurchaseCancelled) {
const cb = listener.onPurchaseCancelled;
handles.push(await nativePlugin.addListener('onPurchaseCancelled', () => {
cb();
}));
}
if (listener.onRestoreStarted) {
const cb = listener.onRestoreStarted;
handles.push(await nativePlugin.addListener('onRestoreStarted', () => {
cb();
}));
}
if (listener.onRestoreCompleted) {
const cb = listener.onRestoreCompleted;
handles.push(await nativePlugin.addListener('onRestoreCompleted', (data) => {
var _a;
cb({ customerInfo: (_a = data.customerInfo) !== null && _a !== void 0 ? _a : data });
}));
}
if (listener.onRestoreError) {
const cb = listener.onRestoreError;
handles.push(await nativePlugin.addListener('onRestoreError', (data) => {
var _a;
cb({ error: (_a = data.error) !== null && _a !== void 0 ? _a : data });
}));
}
}
// Always register onPurchaseInitiated so we auto-resume when the user
// doesn't provide an onPurchaseInitiated callback — otherwise the
// purchase flow hangs waiting for a resume that never comes.
// This must be outside the `if (listener)` block because the native
// delegate adapter always fires this event (even with purchaseLogic only).
const onPurchaseInitiatedCb = listener === null || listener === void 0 ? void 0 : listener.onPurchaseInitiated;
handles.push(await nativePlugin.addListener('onPurchaseInitiated', (data) => {
var _a;
const requestId = data.requestId;
const packageBeingPurchased = (_a = data.package) !== null && _a !== void 0 ? _a : data.packageBeingPurchased;
if (onPurchaseInitiatedCb) {
onPurchaseInitiatedCb({
packageBeingPurchased,
resumable: {
resume(shouldProceed = true) {
nativePlugin.resumePurchaseInitiated({ requestId, shouldProceed });
},
},
});
}
else {
// No callback provided — auto-proceed with the purchase.
nativePlugin.resumePurchaseInitiated({ requestId, shouldProceed: true });
}
}));
// Register PurchaseLogic event handlers
if (purchaseLogic) {
handles.push(await nativePlugin.addListener('onPerformPurchaseRequest', async (data) => {
var _a, _b, _c;
const requestId = data.requestId;
const packageToPurchase = (_b = (_a = data.package) !== null && _a !== void 0 ? _a : data.packageBeingPurchased) !== null && _b !== void 0 ? _b : data.packageToPurchase;
try {
const result = await purchaseLogic.performPurchase({ packageToPurchase });
await nativePlugin.resumePurchaseLogicPurchase(Object.assign({ requestId }, serializeResultForNative(result)));
}
catch (e) {
await nativePlugin.resumePurchaseLogicPurchase({
requestId,
result: PURCHASE_LOGIC_RESULT.ERROR,
error: { message: (_c = e === null || e === void 0 ? void 0 : e.message) !== null && _c !== void 0 ? _c : 'Unknown error' },
});
}
}));
handles.push(await nativePlugin.addListener('onPerformRestoreRequest', async (data) => {
var _a;
const requestId = data.requestId;
try {
const result = await purchaseLogic.performRestore();
await nativePlugin.resumePurchaseLogicRestore(Object.assign({ requestId }, serializeResultForNative(result)));
}
catch (e) {
await nativePlugin.resumePurchaseLogicRestore({
requestId,
result: PURCHASE_LOGIC_RESULT.ERROR,
error: { message: (_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : 'Unknown error' },
});
}
}));
}
// Call native with serializable-only options
const nativeOptions = Object.assign(Object.assign({}, options), { hasPaywallListener: !!listener, hasPurchaseLogic: !!purchaseLogic });
// Remove non-serializable fields
delete nativeOptions.listener;
delete nativeOptions.purchaseLogic;
return await nativeMethod(nativeOptions);
}
finally {
// Clean up all registered listeners
for (const handle of handles) {
await handle.remove();
}
}
}
const RevenueCatUI = {
async presentPaywall(options) {
assertValidPresentationConfiguration(options === null || options === void 0 ? void 0 : options.presentationConfiguration);
const _a = options !== null && options !== void 0 ? options : {}, { presentationConfiguration, listener, purchaseLogic } = _a, rest = __rest(_a, ["presentationConfiguration", "listener", "purchaseLogic"]);
const nativeOpts = Object.assign(Object.assign({}, rest), resolveNativePresentationOptions(presentationConfiguration));
if (!listener && !purchaseLogic) {
return nativePlugin.presentPaywall(nativeOpts);
}
return presentWithListenerSupport((opts) => nativePlugin.presentPaywall(opts), nativeOpts, listener, purchaseLogic);
},
async presentPaywallIfNeeded(options) {
assertValidPresentationConfiguration(options === null || options === void 0 ? void 0 : options.presentationConfiguration);
const { presentationConfiguration, listener, purchaseLogic } = options, rest = __rest(options, ["presentationConfiguration", "listener", "purchaseLogic"]);
const nativeOpts = Object.assign(Object.assign({}, rest), resolveNativePresentationOptions(presentationConfiguration));
if (!listener && !purchaseLogic) {
return nativePlugin.presentPaywallIfNeeded(nativeOpts);
}
return presentWithListenerSupport((opts) => nativePlugin.presentPaywallIfNeeded(opts), nativeOpts, listener, purchaseLogic);
},
async presentCustomerCenter() {
return nativePlugin.presentCustomerCenter();
},
setMockWebResults: nativePlugin.setMockWebResults
? async (options) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return nativePlugin.setMockWebResults(options);
}
: undefined,
addListener(eventName, listener) {
return nativePlugin.addListener(eventName, listener);
},
removeAllListeners() {
return nativePlugin.removeAllListeners();
},
};
export * from './definitions';
export { PAYWALL_RESULT } from '@revenuecat/purchases-typescript-internal-esm';
export { RevenueCatUI };
//# sourceMappingURL=index.js.map