@ridwan-retainer/paywall 0.1.0
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.
- package/README.md +64 -0
- package/dist/__mocks__/async-storage.d.ts +12 -0
- package/dist/__mocks__/async-storage.d.ts.map +1 -0
- package/dist/__mocks__/async-storage.js +14 -0
- package/dist/__mocks__/react-native-purchases-ui.d.ts +17 -0
- package/dist/__mocks__/react-native-purchases-ui.d.ts.map +1 -0
- package/dist/__mocks__/react-native-purchases-ui.js +16 -0
- package/dist/__mocks__/react-native-purchases.d.ts +22 -0
- package/dist/__mocks__/react-native-purchases.d.ts.map +1 -0
- package/dist/__mocks__/react-native-purchases.js +25 -0
- package/dist/components/Paywall.d.ts +13 -0
- package/dist/components/Paywall.d.ts.map +1 -0
- package/dist/components/Paywall.js +18 -0
- package/dist/components/PaywallFooter.d.ts +13 -0
- package/dist/components/PaywallFooter.d.ts.map +1 -0
- package/dist/components/PaywallFooter.js +60 -0
- package/dist/components/PaywallGate.d.ts +12 -0
- package/dist/components/PaywallGate.d.ts.map +1 -0
- package/dist/components/PaywallGate.js +66 -0
- package/dist/components/PurchaseButton.d.ts +13 -0
- package/dist/components/PurchaseButton.d.ts.map +1 -0
- package/dist/components/PurchaseButton.js +30 -0
- package/dist/components/RestoreButton.d.ts +16 -0
- package/dist/components/RestoreButton.d.ts.map +1 -0
- package/dist/components/RestoreButton.js +35 -0
- package/dist/components/SubscriptionGate.d.ts +14 -0
- package/dist/components/SubscriptionGate.d.ts.map +1 -0
- package/dist/components/SubscriptionGate.js +22 -0
- package/dist/config/RevenueCatConfig.d.ts +4 -0
- package/dist/config/RevenueCatConfig.d.ts.map +1 -0
- package/dist/config/RevenueCatConfig.js +61 -0
- package/dist/config/environment.d.ts +3 -0
- package/dist/config/environment.d.ts.map +1 -0
- package/dist/config/environment.js +16 -0
- package/dist/config/types.d.ts +16 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/entitlements/CustomerInfoManager.d.ts +14 -0
- package/dist/entitlements/CustomerInfoManager.d.ts.map +1 -0
- package/dist/entitlements/CustomerInfoManager.js +59 -0
- package/dist/entitlements/EntitlementCache.d.ts +5 -0
- package/dist/entitlements/EntitlementCache.d.ts.map +1 -0
- package/dist/entitlements/EntitlementCache.js +39 -0
- package/dist/entitlements/subscriptionUtils.d.ts +10 -0
- package/dist/entitlements/subscriptionUtils.d.ts.map +1 -0
- package/dist/entitlements/subscriptionUtils.js +34 -0
- package/dist/entitlements/types.d.ts +13 -0
- package/dist/entitlements/types.d.ts.map +1 -0
- package/dist/entitlements/types.js +2 -0
- package/dist/hooks/useCurrentOffering.d.ts +11 -0
- package/dist/hooks/useCurrentOffering.d.ts.map +1 -0
- package/dist/hooks/useCurrentOffering.js +46 -0
- package/dist/hooks/useCustomerInfo.d.ts +8 -0
- package/dist/hooks/useCustomerInfo.d.ts.map +1 -0
- package/dist/hooks/useCustomerInfo.js +34 -0
- package/dist/hooks/useEntitlement.d.ts +10 -0
- package/dist/hooks/useEntitlement.d.ts.map +1 -0
- package/dist/hooks/useEntitlement.js +48 -0
- package/dist/hooks/useOfferings.d.ts +9 -0
- package/dist/hooks/useOfferings.d.ts.map +1 -0
- package/dist/hooks/useOfferings.js +58 -0
- package/dist/hooks/usePaywall.d.ts +6 -0
- package/dist/hooks/usePaywall.d.ts.map +1 -0
- package/dist/hooks/usePaywall.js +23 -0
- package/dist/hooks/usePurchase.d.ts +14 -0
- package/dist/hooks/usePurchase.d.ts.map +1 -0
- package/dist/hooks/usePurchase.js +48 -0
- package/dist/hooks/useRestorePurchases.d.ts +14 -0
- package/dist/hooks/useRestorePurchases.d.ts.map +1 -0
- package/dist/hooks/useRestorePurchases.js +48 -0
- package/dist/hooks/useRevenueCatInitialization.d.ts +5 -0
- package/dist/hooks/useRevenueCatInitialization.d.ts.map +1 -0
- package/dist/hooks/useRevenueCatInitialization.js +44 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/offerings/OfferingsManager.d.ts +12 -0
- package/dist/offerings/OfferingsManager.d.ts.map +1 -0
- package/dist/offerings/OfferingsManager.js +44 -0
- package/dist/offerings/packageUtils.d.ts +11 -0
- package/dist/offerings/packageUtils.d.ts.map +1 -0
- package/dist/offerings/packageUtils.js +44 -0
- package/dist/offerings/types.d.ts +8 -0
- package/dist/offerings/types.d.ts.map +1 -0
- package/dist/offerings/types.js +2 -0
- package/dist/paywall/PaywallController.d.ts +21 -0
- package/dist/paywall/PaywallController.d.ts.map +1 -0
- package/dist/paywall/PaywallController.js +61 -0
- package/dist/paywall/types.d.ts +60 -0
- package/dist/paywall/types.d.ts.map +1 -0
- package/dist/paywall/types.js +10 -0
- package/dist/purchase/PurchaseManager.d.ts +10 -0
- package/dist/purchase/PurchaseManager.d.ts.map +1 -0
- package/dist/purchase/PurchaseManager.js +45 -0
- package/dist/purchase/errorHandling.d.ts +5 -0
- package/dist/purchase/errorHandling.d.ts.map +1 -0
- package/dist/purchase/errorHandling.js +36 -0
- package/dist/purchase/purchaseCache.d.ts +19 -0
- package/dist/purchase/purchaseCache.d.ts.map +1 -0
- package/dist/purchase/purchaseCache.js +57 -0
- package/dist/purchase/types.d.ts +23 -0
- package/dist/purchase/types.d.ts.map +1 -0
- package/dist/purchase/types.js +11 -0
- package/dist/restore/RestoreManager.d.ts +26 -0
- package/dist/restore/RestoreManager.d.ts.map +1 -0
- package/dist/restore/RestoreManager.js +72 -0
- package/dist/restore/autoRestore.d.ts +13 -0
- package/dist/restore/autoRestore.d.ts.map +1 -0
- package/dist/restore/autoRestore.js +37 -0
- package/dist/restore/errorHandling.d.ts +10 -0
- package/dist/restore/errorHandling.d.ts.map +1 -0
- package/dist/restore/errorHandling.js +30 -0
- package/dist/restore/types.d.ts +22 -0
- package/dist/restore/types.d.ts.map +1 -0
- package/dist/restore/types.js +11 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @factory/paywall
|
|
2
|
+
|
|
3
|
+
Revenue-first monetization layer using RevenueCat for in-app purchases and subscriptions in React Native applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- RevenueCat integration for cross-platform subscription management
|
|
8
|
+
- Pre-built paywall UI components
|
|
9
|
+
- Subscription status tracking and management
|
|
10
|
+
- Purchase flow handling with proper error management
|
|
11
|
+
- Offering and package management
|
|
12
|
+
- TypeScript support with full type definitions
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @factory/paywall
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Peer Dependencies
|
|
21
|
+
|
|
22
|
+
This package requires the following peer dependencies:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install react-native-purchases react-native-purchases-ui @react-native-async-storage/async-storage
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
1. Create a RevenueCat account at [revenuecat.com](https://www.revenuecat.com)
|
|
31
|
+
2. Configure your app in the RevenueCat dashboard
|
|
32
|
+
3. Set up your products in App Store Connect and Google Play Console
|
|
33
|
+
4. Link your products to RevenueCat
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { PaywallProvider, usePaywall, PaywallView } from '@factory/paywall';
|
|
39
|
+
|
|
40
|
+
// Wrap your app with PaywallProvider
|
|
41
|
+
function App() {
|
|
42
|
+
return (
|
|
43
|
+
<PaywallProvider revenueCatApiKey="your-api-key">
|
|
44
|
+
<YourApp />
|
|
45
|
+
</PaywallProvider>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Use the paywall hook in your components
|
|
50
|
+
function YourComponent() {
|
|
51
|
+
const { customerInfo, isSubscribed, offerings } = usePaywall();
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<View>
|
|
55
|
+
{!isSubscribed && <PaywallView />}
|
|
56
|
+
{isSubscribed && <Text>Thanks for subscribing!</Text>}
|
|
57
|
+
</View>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const AsyncStorage: {
|
|
2
|
+
setItem: jest.Mock<Promise<void>, [], any>;
|
|
3
|
+
getItem: jest.Mock<Promise<null>, [], any>;
|
|
4
|
+
removeItem: jest.Mock<Promise<void>, [], any>;
|
|
5
|
+
clear: jest.Mock<Promise<void>, [], any>;
|
|
6
|
+
getAllKeys: jest.Mock<Promise<never[]>, [], any>;
|
|
7
|
+
multiGet: jest.Mock<Promise<never[]>, [], any>;
|
|
8
|
+
multiSet: jest.Mock<Promise<void>, [], any>;
|
|
9
|
+
multiRemove: jest.Mock<Promise<void>, [], any>;
|
|
10
|
+
};
|
|
11
|
+
export default AsyncStorage;
|
|
12
|
+
//# sourceMappingURL=async-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-storage.d.ts","sourceRoot":"","sources":["../../src/__mocks__/async-storage.ts"],"names":[],"mappings":"AACA,QAAA,MAAM,YAAY;;;;;;;;;CASjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// Mock for @react-native-async-storage/async-storage
|
|
4
|
+
const AsyncStorage = {
|
|
5
|
+
setItem: jest.fn(() => Promise.resolve()),
|
|
6
|
+
getItem: jest.fn(() => Promise.resolve(null)),
|
|
7
|
+
removeItem: jest.fn(() => Promise.resolve()),
|
|
8
|
+
clear: jest.fn(() => Promise.resolve()),
|
|
9
|
+
getAllKeys: jest.fn(() => Promise.resolve([])),
|
|
10
|
+
multiGet: jest.fn(() => Promise.resolve([])),
|
|
11
|
+
multiSet: jest.fn(() => Promise.resolve()),
|
|
12
|
+
multiRemove: jest.fn(() => Promise.resolve()),
|
|
13
|
+
};
|
|
14
|
+
exports.default = AsyncStorage;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const PAYWALL_RESULT: {
|
|
2
|
+
PURCHASED: string;
|
|
3
|
+
RESTORED: string;
|
|
4
|
+
CANCELLED: string;
|
|
5
|
+
};
|
|
6
|
+
declare const RevenueCatUI: {
|
|
7
|
+
PAYWALL_RESULT: {
|
|
8
|
+
PURCHASED: string;
|
|
9
|
+
RESTORED: string;
|
|
10
|
+
CANCELLED: string;
|
|
11
|
+
};
|
|
12
|
+
presentPaywall: jest.Mock<any, any, any>;
|
|
13
|
+
presentPaywallIfNeeded: jest.Mock<any, any, any>;
|
|
14
|
+
Paywall: string;
|
|
15
|
+
};
|
|
16
|
+
export default RevenueCatUI;
|
|
17
|
+
//# sourceMappingURL=react-native-purchases-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native-purchases-ui.d.ts","sourceRoot":"","sources":["../../src/__mocks__/react-native-purchases-ui.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc;;;;CAI1B,CAAC;AAEF,QAAA,MAAM,YAAY;;;;;;;;;CAKjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PAYWALL_RESULT = void 0;
|
|
4
|
+
// Mock for react-native-purchases-ui
|
|
5
|
+
exports.PAYWALL_RESULT = {
|
|
6
|
+
PURCHASED: 'PURCHASED',
|
|
7
|
+
RESTORED: 'RESTORED',
|
|
8
|
+
CANCELLED: 'CANCELLED',
|
|
9
|
+
};
|
|
10
|
+
const RevenueCatUI = {
|
|
11
|
+
PAYWALL_RESULT: exports.PAYWALL_RESULT,
|
|
12
|
+
presentPaywall: jest.fn(),
|
|
13
|
+
presentPaywallIfNeeded: jest.fn(),
|
|
14
|
+
Paywall: 'Paywall',
|
|
15
|
+
};
|
|
16
|
+
exports.default = RevenueCatUI;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const LOG_LEVEL: {
|
|
2
|
+
VERBOSE: string;
|
|
3
|
+
DEBUG: string;
|
|
4
|
+
INFO: string;
|
|
5
|
+
WARN: string;
|
|
6
|
+
ERROR: string;
|
|
7
|
+
};
|
|
8
|
+
declare const Purchases: {
|
|
9
|
+
setLogLevel: jest.Mock<any, any, any>;
|
|
10
|
+
configure: jest.Mock<any, any, any>;
|
|
11
|
+
getOfferings: jest.Mock<any, any, any>;
|
|
12
|
+
getCustomerInfo: jest.Mock<any, any, any>;
|
|
13
|
+
purchasePackage: jest.Mock<any, any, any>;
|
|
14
|
+
restorePurchases: jest.Mock<any, any, any>;
|
|
15
|
+
syncPurchases: jest.Mock<any, any, any>;
|
|
16
|
+
logIn: jest.Mock<any, any, any>;
|
|
17
|
+
logOut: jest.Mock<any, any, any>;
|
|
18
|
+
addCustomerInfoUpdateListener: jest.Mock<any, any, any>;
|
|
19
|
+
removeCustomerInfoUpdateListener: jest.Mock<any, any, any>;
|
|
20
|
+
};
|
|
21
|
+
export default Purchases;
|
|
22
|
+
//# sourceMappingURL=react-native-purchases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native-purchases.d.ts","sourceRoot":"","sources":["../../src/__mocks__/react-native-purchases.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,SAAS;;;;;;CAMrB,CAAC;AAEF,QAAA,MAAM,SAAS;;;;;;;;;;;;CAYd,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LOG_LEVEL = void 0;
|
|
4
|
+
// Mock for react-native-purchases
|
|
5
|
+
exports.LOG_LEVEL = {
|
|
6
|
+
VERBOSE: 'VERBOSE',
|
|
7
|
+
DEBUG: 'DEBUG',
|
|
8
|
+
INFO: 'INFO',
|
|
9
|
+
WARN: 'WARN',
|
|
10
|
+
ERROR: 'ERROR',
|
|
11
|
+
};
|
|
12
|
+
const Purchases = {
|
|
13
|
+
setLogLevel: jest.fn(),
|
|
14
|
+
configure: jest.fn(),
|
|
15
|
+
getOfferings: jest.fn(),
|
|
16
|
+
getCustomerInfo: jest.fn(),
|
|
17
|
+
purchasePackage: jest.fn(),
|
|
18
|
+
restorePurchases: jest.fn(),
|
|
19
|
+
syncPurchases: jest.fn(),
|
|
20
|
+
logIn: jest.fn(),
|
|
21
|
+
logOut: jest.fn(),
|
|
22
|
+
addCustomerInfoUpdateListener: jest.fn(),
|
|
23
|
+
removeCustomerInfoUpdateListener: jest.fn(),
|
|
24
|
+
};
|
|
25
|
+
exports.default = Purchases;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PaywallCallbacks } from '../paywall/types';
|
|
3
|
+
type PaywallProps = PaywallCallbacks;
|
|
4
|
+
/**
|
|
5
|
+
* RevenueCat Paywall UI Component
|
|
6
|
+
* Official docs: https://www.revenuecat.com/docs/tools/paywalls/displaying-paywalls
|
|
7
|
+
*
|
|
8
|
+
* From docs: "Available listeners: onPurchaseStarted, onPurchaseCompleted,
|
|
9
|
+
* onPurchaseError, onPurchaseCancelled, onRestoreCompleted, onRestoreError, onDismiss"
|
|
10
|
+
*/
|
|
11
|
+
export declare function Paywall({ onPurchaseStarted, onPurchaseCompleted, onPurchaseError, onPurchaseCancelled, onRestoreCompleted, onRestoreError, onDismiss, }: PaywallProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=Paywall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Paywall.d.ts","sourceRoot":"","sources":["../../src/components/Paywall.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,KAAK,YAAY,GAAG,gBAAgB,CAAC;AAErC;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,SAAS,GACV,EAAE,YAAY,qBAYd"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Paywall = Paywall;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const react_native_purchases_ui_1 = __importDefault(require("react-native-purchases-ui"));
|
|
9
|
+
/**
|
|
10
|
+
* RevenueCat Paywall UI Component
|
|
11
|
+
* Official docs: https://www.revenuecat.com/docs/tools/paywalls/displaying-paywalls
|
|
12
|
+
*
|
|
13
|
+
* From docs: "Available listeners: onPurchaseStarted, onPurchaseCompleted,
|
|
14
|
+
* onPurchaseError, onPurchaseCancelled, onRestoreCompleted, onRestoreError, onDismiss"
|
|
15
|
+
*/
|
|
16
|
+
function Paywall({ onPurchaseStarted, onPurchaseCompleted, onPurchaseError, onPurchaseCancelled, onRestoreCompleted, onRestoreError, onDismiss, }) {
|
|
17
|
+
return (<react_native_purchases_ui_1.default.Paywall onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseError={onPurchaseError} onPurchaseCancelled={onPurchaseCancelled} onRestoreCompleted={onRestoreCompleted} onRestoreError={onRestoreError} onDismiss={onDismiss}/>);
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface PaywallFooterProps {
|
|
3
|
+
termsOfServiceUrl?: string;
|
|
4
|
+
privacyPolicyUrl?: string;
|
|
5
|
+
onRestorePress?: () => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Paywall footer with legal links and restore button
|
|
9
|
+
* Required for App Store compliance
|
|
10
|
+
*/
|
|
11
|
+
export declare function PaywallFooter({ termsOfServiceUrl, privacyPolicyUrl, onRestorePress, }: PaywallFooterProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=PaywallFooter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaywallFooter.d.ts","sourceRoot":"","sources":["../../src/components/PaywallFooter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,kBAAkB;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,EAAE,kBAAkB,qBAkCpB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PaywallFooter = PaywallFooter;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
/**
|
|
10
|
+
* Paywall footer with legal links and restore button
|
|
11
|
+
* Required for App Store compliance
|
|
12
|
+
*/
|
|
13
|
+
function PaywallFooter({ termsOfServiceUrl, privacyPolicyUrl, onRestorePress, }) {
|
|
14
|
+
const openUrl = (url) => {
|
|
15
|
+
react_native_1.Linking.openURL(url).catch(err => console.error('Failed to open URL:', err));
|
|
16
|
+
};
|
|
17
|
+
return (<react_native_1.View style={styles.container}>
|
|
18
|
+
{onRestorePress && (<react_native_1.Pressable onPress={onRestorePress} style={styles.restoreButton}>
|
|
19
|
+
<react_native_1.Text style={styles.restoreText}>Restore Purchases</react_native_1.Text>
|
|
20
|
+
</react_native_1.Pressable>)}
|
|
21
|
+
|
|
22
|
+
<react_native_1.View style={styles.linksContainer}>
|
|
23
|
+
{termsOfServiceUrl && (<react_native_1.Pressable onPress={() => openUrl(termsOfServiceUrl)}>
|
|
24
|
+
<react_native_1.Text style={styles.linkText}>Terms of Service</react_native_1.Text>
|
|
25
|
+
</react_native_1.Pressable>)}
|
|
26
|
+
|
|
27
|
+
{termsOfServiceUrl && privacyPolicyUrl && (<react_native_1.Text style={styles.separator}> • </react_native_1.Text>)}
|
|
28
|
+
|
|
29
|
+
{privacyPolicyUrl && (<react_native_1.Pressable onPress={() => openUrl(privacyPolicyUrl)}>
|
|
30
|
+
<react_native_1.Text style={styles.linkText}>Privacy Policy</react_native_1.Text>
|
|
31
|
+
</react_native_1.Pressable>)}
|
|
32
|
+
</react_native_1.View>
|
|
33
|
+
</react_native_1.View>);
|
|
34
|
+
}
|
|
35
|
+
const styles = react_native_1.StyleSheet.create({
|
|
36
|
+
container: {
|
|
37
|
+
padding: 16,
|
|
38
|
+
alignItems: 'center',
|
|
39
|
+
},
|
|
40
|
+
restoreButton: {
|
|
41
|
+
paddingVertical: 8,
|
|
42
|
+
marginBottom: 12,
|
|
43
|
+
},
|
|
44
|
+
restoreText: {
|
|
45
|
+
color: '#007AFF',
|
|
46
|
+
fontSize: 14,
|
|
47
|
+
},
|
|
48
|
+
linksContainer: {
|
|
49
|
+
flexDirection: 'row',
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
},
|
|
52
|
+
linkText: {
|
|
53
|
+
color: '#666',
|
|
54
|
+
fontSize: 12,
|
|
55
|
+
},
|
|
56
|
+
separator: {
|
|
57
|
+
color: '#666',
|
|
58
|
+
fontSize: 12,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
interface PaywallGateProps {
|
|
3
|
+
entitlementId: string;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
onAccessGranted?: () => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Feature gate that shows paywall modal when user lacks entitlement
|
|
9
|
+
*/
|
|
10
|
+
export declare function PaywallGate({ entitlementId, children, onAccessGranted, }: PaywallGateProps): React.JSX.Element | null;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=PaywallGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaywallGate.d.ts","sourceRoot":"","sources":["../../src/components/PaywallGate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAKxD,UAAU,gBAAgB;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,aAAa,EACb,QAAQ,EACR,eAAe,GAChB,EAAE,gBAAgB,4BAmClB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PaywallGate = PaywallGate;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const react_native_1 = require("react-native");
|
|
39
|
+
const useEntitlement_1 = require("../hooks/useEntitlement");
|
|
40
|
+
const Paywall_1 = require("./Paywall");
|
|
41
|
+
/**
|
|
42
|
+
* Feature gate that shows paywall modal when user lacks entitlement
|
|
43
|
+
*/
|
|
44
|
+
function PaywallGate({ entitlementId, children, onAccessGranted, }) {
|
|
45
|
+
const { hasEntitlement, isLoading } = (0, useEntitlement_1.useEntitlement)(entitlementId);
|
|
46
|
+
const [showPaywall, setShowPaywall] = (0, react_1.useState)(false);
|
|
47
|
+
if (isLoading) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (!hasEntitlement) {
|
|
51
|
+
return (<>
|
|
52
|
+
<react_native_1.Modal visible={showPaywall} animationType="slide" presentationStyle="pageSheet" onRequestClose={() => setShowPaywall(false)}>
|
|
53
|
+
<Paywall_1.Paywall onPurchaseCompleted={() => {
|
|
54
|
+
setShowPaywall(false);
|
|
55
|
+
onAccessGranted?.();
|
|
56
|
+
}} onDismiss={() => setShowPaywall(false)}/>
|
|
57
|
+
</react_native_1.Modal>
|
|
58
|
+
|
|
59
|
+
<react_native_1.View>
|
|
60
|
+
{children}
|
|
61
|
+
<react_native_1.Button title="Unlock Feature" onPress={() => setShowPaywall(true)}/>
|
|
62
|
+
</react_native_1.View>
|
|
63
|
+
</>);
|
|
64
|
+
}
|
|
65
|
+
return <>{children}</>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ViewStyle } from 'react-native';
|
|
3
|
+
import type { PurchasesPackage } from 'react-native-purchases';
|
|
4
|
+
interface PurchaseButtonProps {
|
|
5
|
+
package: PurchasesPackage;
|
|
6
|
+
onSuccess?: () => void;
|
|
7
|
+
onError?: (error: Error) => void;
|
|
8
|
+
title?: string;
|
|
9
|
+
style?: ViewStyle;
|
|
10
|
+
}
|
|
11
|
+
export declare function PurchaseButton({ package: pkg, onSuccess, onError, title, style, }: PurchaseButtonProps): React.JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=PurchaseButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PurchaseButton.d.ts","sourceRoot":"","sources":["../../src/components/PurchaseButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK/D,UAAU,mBAAmB;IAC3B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EAAE,GAAG,EACZ,SAAS,EACT,OAAO,EACP,KAAmB,EACnB,KAAK,GACN,EAAE,mBAAmB,qBA+BrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PurchaseButton = PurchaseButton;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
const usePurchase_1 = require("../hooks/usePurchase");
|
|
10
|
+
const errorHandling_1 = require("../purchase/errorHandling");
|
|
11
|
+
function PurchaseButton({ package: pkg, onSuccess, onError, title = 'Subscribe', style, }) {
|
|
12
|
+
const { purchase, isPurchasing } = (0, usePurchase_1.usePurchase)();
|
|
13
|
+
const handlePurchase = async () => {
|
|
14
|
+
try {
|
|
15
|
+
await purchase(pkg);
|
|
16
|
+
onSuccess?.();
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const purchaseError = err instanceof Error
|
|
20
|
+
? { message: err.message, userCancelled: false }
|
|
21
|
+
: { message: 'Purchase failed', userCancelled: false };
|
|
22
|
+
const errorMessage = (0, errorHandling_1.getUserFriendlyErrorMessage)(purchaseError);
|
|
23
|
+
react_native_1.Alert.alert('Purchase Failed', errorMessage);
|
|
24
|
+
onError?.(err instanceof Error ? err : new Error('Purchase failed'));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return (<react_native_1.Pressable onPress={handlePurchase} disabled={isPurchasing} style={style}>
|
|
28
|
+
{isPurchasing ? (<react_native_1.ActivityIndicator />) : (<react_native_1.Text>{title}</react_native_1.Text>)}
|
|
29
|
+
</react_native_1.Pressable>);
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type ViewStyle } from 'react-native';
|
|
3
|
+
interface RestoreButtonProps {
|
|
4
|
+
onSuccess?: () => void;
|
|
5
|
+
onNoPurchases?: () => void;
|
|
6
|
+
onError?: (error: Error) => void;
|
|
7
|
+
title?: string;
|
|
8
|
+
style?: ViewStyle;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Restore Purchases button component
|
|
12
|
+
* Required by Apple App Store Review Guideline 3.1.1
|
|
13
|
+
*/
|
|
14
|
+
export declare function RestoreButton({ onSuccess, onNoPurchases, onError, title, style, }: RestoreButtonProps): React.JSX.Element;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=RestoreButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RestoreButton.d.ts","sourceRoot":"","sources":["../../src/components/RestoreButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzF,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,aAAa,EACb,OAAO,EACP,KAA2B,EAC3B,KAAK,GACN,EAAE,kBAAkB,qBA4CpB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RestoreButton = RestoreButton;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
const useRestorePurchases_1 = require("../hooks/useRestorePurchases");
|
|
10
|
+
/**
|
|
11
|
+
* Restore Purchases button component
|
|
12
|
+
* Required by Apple App Store Review Guideline 3.1.1
|
|
13
|
+
*/
|
|
14
|
+
function RestoreButton({ onSuccess, onNoPurchases, onError, title = 'Restore Purchases', style, }) {
|
|
15
|
+
const { restore, isRestoring, isSuccess, noPurchases } = (0, useRestorePurchases_1.useRestorePurchases)();
|
|
16
|
+
const handleRestore = async () => {
|
|
17
|
+
try {
|
|
18
|
+
await restore();
|
|
19
|
+
if (isSuccess) {
|
|
20
|
+
react_native_1.Alert.alert('Success', 'Your purchases have been restored!', [{ text: 'OK', onPress: onSuccess }]);
|
|
21
|
+
}
|
|
22
|
+
else if (noPurchases) {
|
|
23
|
+
react_native_1.Alert.alert('No Purchases Found', "We couldn't find any previous purchases associated with your account.", [{ text: 'OK', onPress: onNoPurchases }]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const error = err instanceof Error ? err : new Error('Restore failed');
|
|
28
|
+
react_native_1.Alert.alert('Restore Failed', error.message || 'Failed to restore purchases. Please try again.', [{ text: 'OK' }]);
|
|
29
|
+
onError?.(error);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return (<react_native_1.Pressable onPress={handleRestore} disabled={isRestoring} style={style}>
|
|
33
|
+
{isRestoring ? (<react_native_1.ActivityIndicator />) : (<react_native_1.Text>{title}</react_native_1.Text>)}
|
|
34
|
+
</react_native_1.Pressable>);
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React, { type ReactNode } from 'react';
|
|
2
|
+
interface SubscriptionGateProps {
|
|
3
|
+
entitlementId: string;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
fallback?: ReactNode;
|
|
6
|
+
loadingFallback?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Render children only if user has the specified entitlement
|
|
10
|
+
* Official pattern: check entitlement before rendering premium content
|
|
11
|
+
*/
|
|
12
|
+
export declare function SubscriptionGate({ entitlementId, children, fallback, loadingFallback, }: SubscriptionGateProps): React.JSX.Element;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=SubscriptionGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubscriptionGate.d.ts","sourceRoot":"","sources":["../../src/components/SubscriptionGate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9C,UAAU,qBAAqB;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,EACb,QAAQ,EACR,QAAe,EACf,eAAsB,GACvB,EAAE,qBAAqB,qBAYvB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SubscriptionGate = SubscriptionGate;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const useEntitlement_1 = require("../hooks/useEntitlement");
|
|
9
|
+
/**
|
|
10
|
+
* Render children only if user has the specified entitlement
|
|
11
|
+
* Official pattern: check entitlement before rendering premium content
|
|
12
|
+
*/
|
|
13
|
+
function SubscriptionGate({ entitlementId, children, fallback = null, loadingFallback = null, }) {
|
|
14
|
+
const { hasEntitlement, isLoading } = (0, useEntitlement_1.useEntitlement)(entitlementId);
|
|
15
|
+
if (isLoading) {
|
|
16
|
+
return <>{loadingFallback}</>;
|
|
17
|
+
}
|
|
18
|
+
if (!hasEntitlement) {
|
|
19
|
+
return <>{fallback}</>;
|
|
20
|
+
}
|
|
21
|
+
return <>{children}</>;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RevenueCatConfig.d.ts","sourceRoot":"","sources":["../../src/config/RevenueCatConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK9C,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,cAAc,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.initializeRevenueCat = initializeRevenueCat;
|
|
37
|
+
exports.isRevenueCatConfigured = isRevenueCatConfigured;
|
|
38
|
+
const react_native_1 = require("react-native");
|
|
39
|
+
const react_native_purchases_1 = __importStar(require("react-native-purchases"));
|
|
40
|
+
let isConfigured = false;
|
|
41
|
+
// Initialize RevenueCat SDK once per app lifecycle
|
|
42
|
+
async function initializeRevenueCat(config, appUserID) {
|
|
43
|
+
if (isConfigured) {
|
|
44
|
+
console.warn('[RevenueCat] Already initialized');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Enable debug logs in development
|
|
48
|
+
if (__DEV__) {
|
|
49
|
+
react_native_purchases_1.default.setLogLevel(react_native_purchases_1.LOG_LEVEL.DEBUG);
|
|
50
|
+
}
|
|
51
|
+
// Configure with platform-specific API key
|
|
52
|
+
const apiKey = react_native_1.Platform.OS === 'ios' ? config.iosApiKey : config.androidApiKey;
|
|
53
|
+
await react_native_purchases_1.default.configure({
|
|
54
|
+
apiKey,
|
|
55
|
+
appUserID, // Optional: custom user ID or RevenueCat generates anonymous ID
|
|
56
|
+
});
|
|
57
|
+
isConfigured = true;
|
|
58
|
+
}
|
|
59
|
+
function isRevenueCatConfigured() {
|
|
60
|
+
return isConfigured;
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/config/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAqB,MAAM,SAAS,CAAC;AAMjE,wBAAgB,mBAAmB,IAAI,cAAc,CAepD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRevenueCatConfig = getRevenueCatConfig;
|
|
4
|
+
// Load RevenueCat config from environment variables (Expo: EXPO_PUBLIC_ prefix)
|
|
5
|
+
function getRevenueCatConfig() {
|
|
6
|
+
const globalObj = globalThis;
|
|
7
|
+
const iosApiKey = globalObj.process?.env?.EXPO_PUBLIC_REVENUECAT_IOS || '';
|
|
8
|
+
const androidApiKey = globalObj.process?.env?.EXPO_PUBLIC_REVENUECAT_ANDROID || '';
|
|
9
|
+
if (!iosApiKey || !androidApiKey) {
|
|
10
|
+
throw new Error('[RevenueCat] Missing API keys. Set EXPO_PUBLIC_REVENUECAT_IOS and EXPO_PUBLIC_REVENUECAT_ANDROID in .env');
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
iosApiKey,
|
|
14
|
+
androidApiKey,
|
|
15
|
+
};
|
|
16
|
+
}
|