expo-helium 3.0.18 → 3.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"revenuecat.js","sourceRoot":"","sources":["../../src/revenuecat/revenuecat.ts"],"names":[],"mappings":"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","sourcesContent":["import Purchases, {PURCHASES_ERROR_CODE, PurchasesStoreProduct} from 'react-native-purchases';\nimport type { PurchasesError, PurchasesPackage, CustomerInfoUpdateListener, CustomerInfo, PurchasesEntitlementInfo } from 'react-native-purchases';\nimport {HeliumPurchaseConfig, HeliumPurchaseResult} from \"../HeliumPaywallSdk.types\";\nimport {setRevenueCatAppUserId} from \"../index\";\n\n// Rename the factory function\nexport function createRevenueCatPurchaseConfig(config?: {\n apiKey?: string;\n}): HeliumPurchaseConfig {\n const rcHandler = new RevenueCatHeliumHandler(config?.apiKey);\n return {\n makePurchase: rcHandler.makePurchase.bind(rcHandler),\n restorePurchases: rcHandler.restorePurchases.bind(rcHandler),\n };\n}\n\nexport class RevenueCatHeliumHandler {\n private productIdToPackageMapping: Record<string, PurchasesPackage> = {};\n private isMappingInitialized: boolean = false;\n private initializationPromise: Promise<void> | null = null;\n\n private rcProductToPackageMapping: Record<string, PurchasesStoreProduct> = {};\n\n constructor(apiKey?: string) {\n if (apiKey) {\n Purchases.configure({ apiKey });\n }\n void this.initializePackageMapping();\n }\n\n private async initializePackageMapping(): Promise<void> {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n this.initializationPromise = (async () => {\n try {\n // Keep this value as up-to-date as possible\n setRevenueCatAppUserId(await Purchases.getAppUserID());\n\n const offerings = await Purchases.getOfferings();\n const allOfferings = offerings.all;\n for (const offering of Object.values(allOfferings)) {\n offering.availablePackages.forEach((pkg: PurchasesPackage) => {\n if (pkg.product?.identifier) {\n this.productIdToPackageMapping[pkg.product.identifier] = pkg;\n }\n });\n }\n this.isMappingInitialized = true;\n } catch (error) {\n this.isMappingInitialized = false;\n } finally {\n this.initializationPromise = null;\n }\n })();\n return this.initializationPromise;\n }\n\n private async ensureMappingInitialized(): Promise<void> {\n if (!this.isMappingInitialized && !this.initializationPromise) {\n await this.initializePackageMapping();\n } else if (this.initializationPromise) {\n await this.initializationPromise;\n }\n }\n\n async makePurchase(productId: string): Promise<HeliumPurchaseResult> {\n await this.ensureMappingInitialized();\n // Keep this value as up-to-date as possible\n setRevenueCatAppUserId(await Purchases.getAppUserID());\n\n const pkg: PurchasesPackage | undefined = this.productIdToPackageMapping[productId];\n let rcProduct: PurchasesStoreProduct | undefined;\n if (!pkg) {\n // Use cached if available\n rcProduct = this.rcProductToPackageMapping[productId];\n if (!rcProduct) {\n // Try to retrieve now\n try {\n const rcProducts = await Purchases.getProducts([productId]);\n rcProduct = rcProducts.length > 0 ? rcProducts[0] : undefined;\n } catch {\n // 'failed' status will be returned\n }\n if (rcProduct) {\n this.rcProductToPackageMapping[productId] = rcProduct;\n }\n }\n }\n\n try {\n let customerInfo: CustomerInfo;\n if (pkg) {\n customerInfo = (await Purchases.purchasePackage(pkg)).customerInfo;\n } else if (rcProduct) {\n customerInfo = (await Purchases.purchaseStoreProduct(rcProduct)).customerInfo;\n } else {\n return { status: 'failed', error: `RevenueCat Product/Package not found for ID: ${productId}` };\n }\n const isActive = this.isProductActive(customerInfo, productId);\n if (isActive) {\n return { status: 'purchased' };\n } else {\n // This case might occur if the purchase succeeded but the entitlement wasn't immediately active\n // or if a different product became active.\n // Consider if polling/listening might be needed here too, similar to pending.\n // For now, returning failed as the specific product isn't confirmed active.\n return { status: 'failed', error: 'Purchase possibly complete but entitlement/subscription not active for this product.' };\n }\n } catch (error) {\n const purchasesError = error as PurchasesError;\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR) {\n // Wait for a terminal state for up to 5 seconds\n return new Promise((resolve) => {\n // Define the listener function separately to remove it later\n const updateListener: CustomerInfoUpdateListener = (updatedCustomerInfo: CustomerInfo) => {\n const isActive = this.isProductActive(updatedCustomerInfo, productId);\n if (isActive) {\n clearTimeout(timeoutId);\n // Remove listener using the function reference\n Purchases.removeCustomerInfoUpdateListener(updateListener);\n resolve({ status: 'purchased' });\n }\n };\n\n const timeoutId = setTimeout(() => {\n // Remove listener using the function reference on timeout\n Purchases.removeCustomerInfoUpdateListener(updateListener);\n resolve({ status: 'pending' });\n }, 5000);\n\n // Add the listener\n Purchases.addCustomerInfoUpdateListener(updateListener);\n });\n }\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {\n return { status: 'cancelled' };\n }\n\n // Handle other errors\n return { status: 'failed', error: purchasesError?.message || 'RevenueCat purchase failed.' };\n }\n }\n\n // Helper function to check if a product is active in CustomerInfo\n private isProductActive(customerInfo: CustomerInfo, productId: string): boolean {\n return Object.values(customerInfo.entitlements.active).some((entitlement: PurchasesEntitlementInfo) => entitlement.productIdentifier === productId)\n || customerInfo.activeSubscriptions.includes(productId)\n || customerInfo.allPurchasedProductIdentifiers.includes(productId);\n }\n\n async restorePurchases(): Promise<boolean> {\n try {\n const customerInfo = await Purchases.restorePurchases();\n const isActive = Object.keys(customerInfo.entitlements.active).length > 0;\n return isActive;\n } catch (error) {\n return false;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"revenuecat.js","sourceRoot":"","sources":["../../src/revenuecat/revenuecat.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CustomerInfo,\n PurchasesEntitlementInfo,\n PurchasesError,\n PurchasesPackage,\n SubscriptionOption\n} from 'react-native-purchases';\nimport Purchases, {PURCHASES_ERROR_CODE, PurchasesStoreProduct} from 'react-native-purchases';\nimport {Platform} from 'react-native';\nimport {HeliumPurchaseConfig, HeliumPurchaseResult} from \"../HeliumPaywallSdk.types\";\nimport {setRevenueCatAppUserId} from \"../index\";\n\n// Rename the factory function\nexport function createRevenueCatPurchaseConfig(config?: {\n apiKey?: string;\n apiKeyIOS?: string;\n apiKeyAndroid?: string;\n}): HeliumPurchaseConfig {\n const rcHandler = new RevenueCatHeliumHandler(config);\n return {\n makePurchaseIOS: rcHandler.makePurchaseIOS.bind(rcHandler),\n makePurchaseAndroid: rcHandler.makePurchaseAndroid.bind(rcHandler),\n restorePurchases: rcHandler.restorePurchases.bind(rcHandler),\n };\n}\n\nexport class RevenueCatHeliumHandler {\n private productIdToPackageMapping: Record<string, PurchasesPackage> = {};\n private isMappingInitialized: boolean = false;\n private initializationPromise: Promise<void> | null = null;\n\n private rcProductToPackageMapping: Record<string, PurchasesStoreProduct> = {};\n\n constructor(config?: { apiKey?: string; apiKeyIOS?: string; apiKeyAndroid?: string }) {\n // Determine which API key to use based on platform\n let effectiveApiKey: string | undefined;\n if (Platform.OS === 'ios' && config?.apiKeyIOS) {\n effectiveApiKey = config.apiKeyIOS;\n } else if (Platform.OS === 'android' && config?.apiKeyAndroid) {\n effectiveApiKey = config.apiKeyAndroid;\n } else {\n effectiveApiKey = config?.apiKey;\n }\n\n if (effectiveApiKey) {\n Purchases.configure({apiKey: effectiveApiKey});\n }\n void this.initializePackageMapping();\n }\n\n private async initializePackageMapping(): Promise<void> {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n this.initializationPromise = (async () => {\n try {\n // Keep this value as up-to-date as possible\n setRevenueCatAppUserId(await Purchases.getAppUserID());\n\n const offerings = await Purchases.getOfferings();\n const allOfferings = offerings.all;\n for (const offering of Object.values(allOfferings)) {\n offering.availablePackages.forEach((pkg: PurchasesPackage) => {\n if (pkg.product?.identifier) {\n this.productIdToPackageMapping[pkg.product.identifier] = pkg;\n }\n });\n }\n this.isMappingInitialized = true;\n } catch (error) {\n this.isMappingInitialized = false;\n } finally {\n this.initializationPromise = null;\n }\n })();\n return this.initializationPromise;\n }\n\n private async ensureMappingInitialized(): Promise<void> {\n if (!this.isMappingInitialized && !this.initializationPromise) {\n await this.initializePackageMapping();\n } else if (this.initializationPromise) {\n await this.initializationPromise;\n }\n }\n\n async makePurchaseIOS(productId: string): Promise<HeliumPurchaseResult> {\n // Keep this value as up-to-date as possible\n setRevenueCatAppUserId(await Purchases.getAppUserID());\n\n await this.ensureMappingInitialized();\n const pkg: PurchasesPackage | undefined = this.productIdToPackageMapping[productId];\n let rcProduct: PurchasesStoreProduct | undefined;\n if (!pkg) {\n // Use cached if available\n rcProduct = this.rcProductToPackageMapping[productId];\n if (!rcProduct) {\n // Try to retrieve now\n try {\n const rcProducts = await Purchases.getProducts([productId]);\n rcProduct = rcProducts.length > 0 ? rcProducts[0] : undefined;\n } catch {\n // 'failed' status will be returned\n }\n if (rcProduct) {\n this.rcProductToPackageMapping[productId] = rcProduct;\n }\n }\n }\n\n try {\n let customerInfo: CustomerInfo;\n if (pkg) {\n customerInfo = (await Purchases.purchasePackage(pkg)).customerInfo;\n } else if (rcProduct) {\n customerInfo = (await Purchases.purchaseStoreProduct(rcProduct)).customerInfo;\n } else {\n return {status: 'failed', error: `RevenueCat Product/Package not found for ID: ${productId}`};\n }\n const isActive = this.isProductActive(customerInfo, productId);\n if (isActive) {\n return {status: 'purchased'};\n } else {\n // This case might occur if the purchase succeeded but the entitlement wasn't immediately active\n // or if a different product became active.\n // Consider if polling/listening might be needed here too, similar to pending.\n // For now, returning failed as the specific product isn't confirmed active.\n return {\n status: 'failed',\n error: 'Purchase possibly complete but entitlement/subscription not active for this product.'\n };\n }\n } catch (error) {\n const purchasesError = error as PurchasesError;\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR) {\n return {status: 'pending'};\n }\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {\n return {status: 'cancelled'};\n }\n\n // Handle other errors\n return {status: 'failed', error: purchasesError?.message || 'RevenueCat purchase failed.'};\n }\n }\n\n // Android-specific purchase logic (completely separated from iOS)\n async makePurchaseAndroid(productId: string, basePlanId?: string, offerId?: string): Promise<HeliumPurchaseResult> {\n // Keep this value as up-to-date as possible\n setRevenueCatAppUserId(await Purchases.getAppUserID());\n\n // Handle subscription with base plan or offer\n if (basePlanId || offerId) {\n const subscriptionOption = await this.findAndroidSubscriptionOption(\n productId,\n basePlanId,\n offerId\n );\n\n if (subscriptionOption) {\n try {\n const customerInfo = (await Purchases.purchaseSubscriptionOption(subscriptionOption)).customerInfo;\n\n const isActive = this.isProductActive(customerInfo, productId);\n if (isActive) {\n return {status: 'purchased'};\n } else {\n return {\n status: 'failed',\n error: 'Purchase possibly complete but entitlement/subscription not active for this product.'\n };\n }\n } catch (error) {\n const purchasesError = error as PurchasesError;\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR) {\n return {status: 'pending'};\n }\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {\n return {status: 'cancelled'};\n }\n\n return {status: 'failed', error: purchasesError?.message || 'RevenueCat purchase failed.'};\n }\n }\n }\n\n // Handle one-time purchase or subscription that didn't have matching base plan / offer\n let rcProduct: PurchasesStoreProduct;\n try {\n const products = await Purchases.getProducts([productId]);\n if (products.length === 0) {\n return {status: 'failed', error: `Android product not found: ${productId}`};\n }\n rcProduct = products[0];\n } catch {\n return {status: 'failed', error: `Failed to retrieve Android product: ${productId}`};\n }\n\n try {\n const customerInfo = (await Purchases.purchaseStoreProduct(rcProduct)).customerInfo;\n\n const isActive = this.isProductActive(customerInfo, productId);\n if (isActive) {\n return {status: 'purchased'};\n } else {\n return {\n status: 'failed',\n error: 'Purchase possibly complete but entitlement/subscription not active for this product.'\n };\n }\n } catch (error) {\n const purchasesError = error as PurchasesError;\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PAYMENT_PENDING_ERROR) {\n return {status: 'pending'};\n }\n\n if (purchasesError?.code === PURCHASES_ERROR_CODE.PURCHASE_CANCELLED_ERROR) {\n return {status: 'cancelled'};\n }\n\n return {status: 'failed', error: purchasesError?.message || 'RevenueCat purchase failed.'};\n }\n }\n\n // Android helper: Find subscription option\n private async findAndroidSubscriptionOption(\n productId: string,\n basePlanId?: string,\n offerId?: string\n ): Promise<SubscriptionOption | undefined> {\n try {\n const products = await Purchases.getProducts([productId]);\n if (products.length === 0) {\n return undefined;\n }\n\n const product = products[0];\n\n if (!product.subscriptionOptions || product.subscriptionOptions.length === 0) {\n return undefined;\n }\n\n let subscriptionOption: SubscriptionOption | undefined;\n\n if (offerId && basePlanId) {\n // Look for specific offer: \"basePlanId:offerId\"\n const targetId = `${basePlanId}:${offerId}`;\n subscriptionOption = product.subscriptionOptions.find(opt => opt.id === targetId);\n } else if (basePlanId) {\n subscriptionOption = product.subscriptionOptions.find(\n opt => opt.id === basePlanId && opt.isBasePlan\n );\n }\n\n return subscriptionOption;\n } catch (error) {\n return undefined;\n }\n }\n\n // Helper function to check if a product is active in CustomerInfo\n private isProductActive(customerInfo: CustomerInfo, productId: string): boolean {\n return Object.values(customerInfo.entitlements.active).some((entitlement: PurchasesEntitlementInfo) => entitlement.productIdentifier === productId)\n || customerInfo.activeSubscriptions.includes(productId)\n || customerInfo.allPurchasedProductIdentifiers.includes(productId);\n }\n\n async restorePurchases(): Promise<boolean> {\n try {\n const customerInfo = await Purchases.restorePurchases();\n const isActive = Object.keys(customerInfo.entitlements.active).length > 0;\n return isActive;\n } catch (error) {\n return false;\n }\n }\n}\n"]}
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
19
19
  s.static_framework = true
20
20
 
21
21
  s.dependency 'ExpoModulesCore'
22
- s.dependency 'Helium', '3.1.1'
22
+ s.dependency 'Helium', '3.1.2'
23
23
 
24
24
  # Swift/Objective-C compatibility
25
25
  s.pod_target_xcconfig = {
@@ -43,13 +43,11 @@ private class NativeModuleManager {
43
43
  // Store active operations
44
44
  var activePurchaseContinuation: CheckedContinuation<HeliumPaywallTransactionStatus, Never>?
45
45
  var activeRestoreContinuation: CheckedContinuation<Bool, Never>?
46
- var currentProductId: String?
47
46
 
48
47
  private init() {}
49
48
 
50
49
  func clearPurchase() {
51
50
  activePurchaseContinuation = nil
52
- currentProductId = nil
53
51
  }
54
52
 
55
53
  func clearRestore() {
@@ -140,7 +138,6 @@ public class HeliumPaywallSdkModule: Module {
140
138
 
141
139
  return await withCheckedContinuation { continuation in
142
140
  NativeModuleManager.shared.activePurchaseContinuation = continuation
143
- NativeModuleManager.shared.currentProductId = productId
144
141
 
145
142
  // Send event to JavaScript
146
143
  module.sendEvent("onDelegateActionEvent", [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-helium",
3
- "version": "3.0.18",
3
+ "version": "3.1.1",
4
4
  "description": "Helium paywalls expo sdk",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -52,9 +52,19 @@ export interface VariantDetails {
52
52
  */
53
53
  export interface ExperimentInfo {
54
54
  /**
55
- * Trigger name at which user was enrolled
55
+ * @deprecated Use `enrolledTrigger` instead.
56
56
  */
57
- trigger: string;
57
+ trigger?: string;
58
+
59
+ /**
60
+ * Trigger where this user was enrolled
61
+ */
62
+ enrolledTrigger?: string;
63
+
64
+ /**
65
+ * All triggers where this experiment is configured
66
+ */
67
+ triggers?: string[];
58
68
 
59
69
  /**
60
70
  * Experiment name
@@ -58,6 +58,10 @@ export type HeliumPaywallEvent = {
58
58
  export type DelegateActionEvent = {
59
59
  type: 'purchase' | 'restore';
60
60
  productId?: string;
61
+ /** Android-specific: Base plan ID for subscriptions */
62
+ basePlanId?: string;
63
+ /** Android-specific: Offer ID for promotional offers */
64
+ offerId?: string;
61
65
  };
62
66
 
63
67
  export type HeliumPaywallSdkViewProps = {
@@ -73,26 +77,43 @@ export type HeliumPurchaseResult = {
73
77
  };
74
78
  export type HeliumDownloadStatus = 'downloadSuccess' | 'downloadFailure' | 'inProgress' | 'notDownloadedYet';
75
79
  export type HeliumLightDarkMode = 'light' | 'dark' | 'system';
80
+ export type HeliumEnvironment = 'sandbox' | 'production';
76
81
 
77
82
  // --- Purchase Configuration Types ---
78
83
 
79
84
  /** Interface for providing custom purchase handling logic. */
80
-
81
85
  export interface HeliumPurchaseConfig {
82
- makePurchase: (productId: string) => Promise<HeliumPurchaseResult>;
86
+ /**
87
+ * @deprecated Use makePurchaseIOS / makePurchaseAndroid instead for platform-specific handling.
88
+ * This method will continue to work for backward compatibility but doesn't provide Android subscription parameters.
89
+ */
90
+ makePurchase?: (productId: string) => Promise<HeliumPurchaseResult>;
91
+
92
+ /** iOS-specific purchase handler. Receives a simple product ID string. */
93
+ makePurchaseIOS?: (productId: string) => Promise<HeliumPurchaseResult>;
94
+
95
+ /** Android-specific purchase handler. Receives product ID and optional subscription parameters. */
96
+ makePurchaseAndroid?: (productId: string, basePlanId?: string, offerId?: string) => Promise<HeliumPurchaseResult>;
97
+
83
98
  restorePurchases: () => Promise<boolean>;
84
99
  }
85
100
 
86
101
  // Helper function for creating Custom Purchase Config
87
102
  export function createCustomPurchaseConfig(callbacks: {
88
- makePurchase: (productId: string) => Promise<HeliumPurchaseResult>;
103
+ /** @deprecated Use makePurchaseIOS or makePurchaseAndroid instead */
104
+ makePurchase?: (productId: string) => Promise<HeliumPurchaseResult>;
105
+ makePurchaseIOS?: (productId: string) => Promise<HeliumPurchaseResult>;
106
+ makePurchaseAndroid?: (productId: string, basePlanId?: string, offerId?: string) => Promise<HeliumPurchaseResult>;
89
107
  restorePurchases: () => Promise<boolean>;
90
108
  }): HeliumPurchaseConfig {
91
109
  return {
92
110
  makePurchase: callbacks.makePurchase,
111
+ makePurchaseIOS: callbacks.makePurchaseIOS,
112
+ makePurchaseAndroid: callbacks.makePurchaseAndroid,
93
113
  restorePurchases: callbacks.restorePurchases,
94
114
  };
95
115
  }
116
+ //wtf do we even have createCustomPurchaseConfig...
96
117
 
97
118
  export type TriggerLoadingConfig = {
98
119
  /** Whether to show loading state for this trigger. Set to nil to use the global `useLoadingState` setting. */
@@ -139,6 +160,11 @@ export interface HeliumConfig {
139
160
  fallbackBundle?: object;
140
161
  /** Configure loading behavior for paywalls that are mid-download. */
141
162
  paywallLoadingConfig?: HeliumPaywallLoadingConfig;
163
+ /** Environment to use for Android. (iOS auto-detects this.)
164
+ * If not specified, Android environment will be "sandbox" if app is a debug build, "production otherwise".
165
+ * Recommended to pass in "sandbox" for QA builds that behave like a production build but are actually just for testing.
166
+ */
167
+ environment?: HeliumEnvironment;
142
168
  customUserId?: string;
143
169
  customAPIEndpoint?: string;
144
170
  customUserTraits?: Record<string, any>;
@@ -155,6 +181,7 @@ export interface NativeHeliumConfig {
155
181
  fallbackBundleString?: string;
156
182
  paywallLoadingConfig?: HeliumPaywallLoadingConfig;
157
183
  useDefaultDelegate?: boolean;
184
+ environment?: string;
158
185
  }
159
186
 
160
187
  export type PresentUpsellParams = {
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import { ExperimentInfo } from "./HeliumExperimentInfo.types";
8
8
  import HeliumPaywallSdkModule from "./HeliumPaywallSdkModule";
9
9
  import { EventSubscription } from 'expo-modules-core';
10
10
  import * as ExpoFileSystem from 'expo-file-system';
11
+ import { Platform } from 'react-native';
11
12
 
12
13
  export { default } from './HeliumPaywallSdkModule';
13
14
  // export { default as HeliumPaywallSdkView } from './HeliumPaywallSdkView';
@@ -49,12 +50,44 @@ export const initialize = (config: HeliumConfig) => {
49
50
  addDelegateActionEventListener(async (event) => {
50
51
  try {
51
52
  if (event.type === 'purchase') {
52
- if (event.productId) {
53
- const result = await purchaseConfig.makePurchase(event.productId);
54
- HeliumPaywallSdkModule.handlePurchaseResult(result.status, result.error);
55
- } else {
53
+ if (!event.productId) {
56
54
  HeliumPaywallSdkModule.handlePurchaseResult('failed', 'No product ID for purchase event.');
55
+ return;
57
56
  }
57
+
58
+ let result;
59
+
60
+ // Platform-specific purchase handling
61
+ if (Platform.OS === 'ios') {
62
+ // iOS: Use makePurchaseIOS if available, otherwise use deprecated makePurchase
63
+ if (purchaseConfig.makePurchaseIOS) {
64
+ result = await purchaseConfig.makePurchaseIOS(event.productId);
65
+ } else if (purchaseConfig.makePurchase) {
66
+ result = await purchaseConfig.makePurchase(event.productId);
67
+ } else {
68
+ console.log('[Helium] No iOS purchase handler configured.');
69
+ HeliumPaywallSdkModule.handlePurchaseResult('failed', 'No iOS purchase handler configured.');
70
+ return;
71
+ }
72
+ } else if (Platform.OS === 'android') {
73
+ // Android: Use makePurchaseAndroid if available
74
+ if (purchaseConfig.makePurchaseAndroid) {
75
+ result = await purchaseConfig.makePurchaseAndroid(
76
+ event.productId,
77
+ event.basePlanId,
78
+ event.offerId
79
+ );
80
+ } else {
81
+ console.log('[Helium] No Android purchase handler configured.');
82
+ HeliumPaywallSdkModule.handlePurchaseResult('failed', 'No Android purchase handler configured.');
83
+ return;
84
+ }
85
+ } else {
86
+ HeliumPaywallSdkModule.handlePurchaseResult('failed', 'Unsupported platform.');
87
+ return;
88
+ }
89
+
90
+ HeliumPaywallSdkModule.handlePurchaseResult(result.status, result.error);
58
91
  } else if (event.type === 'restore') {
59
92
  const success = await purchaseConfig.restorePurchases();
60
93
  HeliumPaywallSdkModule.handleRestoreResult(success);
@@ -115,6 +148,7 @@ const nativeInitializeAsync = async (config: HeliumConfig) => {
115
148
  fallbackBundleString: fallbackBundleString,
116
149
  paywallLoadingConfig: convertBooleansToMarkers(config.paywallLoadingConfig),
117
150
  useDefaultDelegate: !config.purchaseConfig,
151
+ environment: config.environment,
118
152
  };
119
153
 
120
154
  // Initialize the native module
@@ -297,11 +331,12 @@ export const getExperimentInfoForTrigger = (trigger: string): ExperimentInfo | u
297
331
  return;
298
332
  }
299
333
  if (result.getExperimentInfoErrorMsg) {
334
+ console.log(`[Helium] getExperimentInfoForTrigger bridging error. ${result.getExperimentInfoErrorMsg}`);
300
335
  return;
301
336
  }
302
337
  // Validate required field exists before casting
303
- if (!result.trigger) {
304
- console.log('[Helium] getExperimentInfoForTrigger returned data without required trigger field.');
338
+ if (!result.experimentId) {
339
+ console.log('[Helium] getExperimentInfoForTrigger returned data without required experimentId field.');
305
340
  return;
306
341
  }
307
342
  return result as ExperimentInfo;