@billdog.io/react-native 1.0.0-beta.2
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/BillDogReactNative.podspec +30 -0
- package/LICENSE +21 -0
- package/README.md +330 -0
- package/android/build.gradle +99 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogABTestModule.kt +317 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogAnalyticsModule.kt +389 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogModule.kt +817 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogPaywallViewManager.kt +383 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogSurveyModule.kt +427 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogVirtualCurrencyModule.kt +407 -0
- package/android/src/main/kotlin/io/billdog/virtualcurrency/BillDogVirtualCurrencyPackage.kt +44 -0
- package/dist/AdvancedPaywallCache.d.ts +70 -0
- package/dist/AdvancedPaywallCache.js +344 -0
- package/dist/BillDog.d.ts +255 -0
- package/dist/BillDog.js +918 -0
- package/dist/BillDogConfiguration.d.ts +145 -0
- package/dist/BillDogConfiguration.js +229 -0
- package/dist/ComponentRenderer.d.ts +17 -0
- package/dist/ComponentRenderer.js +886 -0
- package/dist/LayoutEngine.d.ts +101 -0
- package/dist/LayoutEngine.js +394 -0
- package/dist/LocalizationResolver.d.ts +99 -0
- package/dist/LocalizationResolver.js +266 -0
- package/dist/NativePaywallView.d.ts +36 -0
- package/dist/NativePaywallView.js +59 -0
- package/dist/PaywallCache.d.ts +74 -0
- package/dist/PaywallCache.js +293 -0
- package/dist/PaywallStateManager.d.ts +62 -0
- package/dist/PaywallStateManager.js +147 -0
- package/dist/PaywallView.d.ts +42 -0
- package/dist/PaywallView.js +275 -0
- package/dist/ProductVariableProvider.d.ts +60 -0
- package/dist/ProductVariableProvider.js +239 -0
- package/dist/VariableResolver.d.ts +120 -0
- package/dist/VariableResolver.js +379 -0
- package/dist/WebViewPaywall.d.ts +75 -0
- package/dist/WebViewPaywall.js +360 -0
- package/dist/animations/presets.d.ts +49 -0
- package/dist/animations/presets.js +367 -0
- package/dist/components/AccoladeCpsComponent.d.ts +13 -0
- package/dist/components/AccoladeCpsComponent.js +248 -0
- package/dist/components/AccordionComponent.d.ts +10 -0
- package/dist/components/AccordionComponent.js +187 -0
- package/dist/components/AnimatedWrapper.d.ts +35 -0
- package/dist/components/AnimatedWrapper.js +277 -0
- package/dist/components/CarouselComponent.d.ts +23 -0
- package/dist/components/CarouselComponent.js +484 -0
- package/dist/components/ChartCurveComponent.d.ts +13 -0
- package/dist/components/ChartCurveComponent.js +333 -0
- package/dist/components/CheckboxComponent.d.ts +9 -0
- package/dist/components/CheckboxComponent.js +172 -0
- package/dist/components/ConfettiComponent.d.ts +9 -0
- package/dist/components/ConfettiComponent.js +172 -0
- package/dist/components/CountdownComponent.d.ts +16 -0
- package/dist/components/CountdownComponent.js +414 -0
- package/dist/components/DelayedXComponent.d.ts +12 -0
- package/dist/components/DelayedXComponent.js +240 -0
- package/dist/components/DrawerModalComponent.d.ts +20 -0
- package/dist/components/DrawerModalComponent.js +286 -0
- package/dist/components/GradientView.d.ts +38 -0
- package/dist/components/GradientView.js +126 -0
- package/dist/components/HapticFeedbackComponent.d.ts +16 -0
- package/dist/components/HapticFeedbackComponent.js +64 -0
- package/dist/components/HorizontalProductsComponent.d.ts +17 -0
- package/dist/components/HorizontalProductsComponent.js +284 -0
- package/dist/components/MultiChoiceGridComponent.d.ts +13 -0
- package/dist/components/MultiChoiceGridComponent.js +234 -0
- package/dist/components/NPSScaleComponent.d.ts +16 -0
- package/dist/components/NPSScaleComponent.js +260 -0
- package/dist/components/NavigationComponent.d.ts +26 -0
- package/dist/components/NavigationComponent.js +302 -0
- package/dist/components/OAuthButtonComponent.d.ts +20 -0
- package/dist/components/OAuthButtonComponent.js +237 -0
- package/dist/components/ProgressLoaderComponent.d.ts +13 -0
- package/dist/components/ProgressLoaderComponent.js +308 -0
- package/dist/components/ProgressStepperComponent.d.ts +18 -0
- package/dist/components/ProgressStepperComponent.js +228 -0
- package/dist/components/SegmentedPickerComponent.d.ts +10 -0
- package/dist/components/SegmentedPickerComponent.js +221 -0
- package/dist/components/ShareButtonsComponent.d.ts +21 -0
- package/dist/components/ShareButtonsComponent.js +265 -0
- package/dist/components/ShareCodeComponent.d.ts +16 -0
- package/dist/components/ShareCodeComponent.js +274 -0
- package/dist/components/SingleChoiceGridComponent.d.ts +13 -0
- package/dist/components/SingleChoiceGridComponent.js +210 -0
- package/dist/components/SliderComponent.d.ts +9 -0
- package/dist/components/SliderComponent.js +263 -0
- package/dist/components/StarRatingInputComponent.d.ts +20 -0
- package/dist/components/StarRatingInputComponent.js +198 -0
- package/dist/components/StickerCompositeComponent.d.ts +13 -0
- package/dist/components/StickerCompositeComponent.js +136 -0
- package/dist/components/TabsComponent.d.ts +19 -0
- package/dist/components/TabsComponent.js +431 -0
- package/dist/components/TextInputComponent.d.ts +18 -0
- package/dist/components/TextInputComponent.js +227 -0
- package/dist/components/TimelineComponent.d.ts +19 -0
- package/dist/components/TimelineComponent.js +104 -0
- package/dist/components/ToggleComponent.d.ts +14 -0
- package/dist/components/ToggleComponent.js +132 -0
- package/dist/components/VerticalProductsComponent.d.ts +17 -0
- package/dist/components/VerticalProductsComponent.js +311 -0
- package/dist/dynamicValues.d.ts +36 -0
- package/dist/dynamicValues.js +142 -0
- package/dist/filters/dateFilters.d.ts +50 -0
- package/dist/filters/dateFilters.js +390 -0
- package/dist/filters/index.d.ts +18 -0
- package/dist/filters/index.js +253 -0
- package/dist/hooks/useOfferings.d.ts +76 -0
- package/dist/hooks/useOfferings.js +99 -0
- package/dist/hooks/usePaywall.d.ts +27 -0
- package/dist/hooks/usePaywall.js +114 -0
- package/dist/hooks/usePlacement.d.ts +34 -0
- package/dist/hooks/usePlacement.js +89 -0
- package/dist/hooks/useSubscription.d.ts +40 -0
- package/dist/hooks/useSubscription.js +97 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +198 -0
- package/dist/models/BillDogError.d.ts +40 -0
- package/dist/models/BillDogError.js +11 -0
- package/dist/models/CacheFetchPolicy.d.ts +8 -0
- package/dist/models/CacheFetchPolicy.js +4 -0
- package/dist/models/CustomProduct.d.ts +32 -0
- package/dist/models/CustomProduct.js +15 -0
- package/dist/models/CustomerInfo.d.ts +17 -0
- package/dist/models/CustomerInfo.js +11 -0
- package/dist/models/Delegate.d.ts +20 -0
- package/dist/models/Delegate.js +11 -0
- package/dist/models/EntitlementInfo.d.ts +19 -0
- package/dist/models/EntitlementInfo.js +2 -0
- package/dist/models/Placement.d.ts +54 -0
- package/dist/models/Placement.js +15 -0
- package/dist/models/PurchaseParams.d.ts +39 -0
- package/dist/models/PurchaseParams.js +60 -0
- package/dist/models/PurchaseResult.d.ts +30 -0
- package/dist/models/PurchaseResult.js +15 -0
- package/dist/models/RestoreResult.d.ts +30 -0
- package/dist/models/RestoreResult.js +22 -0
- package/dist/models/RestoredItem.d.ts +26 -0
- package/dist/models/RestoredItem.js +13 -0
- package/dist/modules/ABTest.d.ts +65 -0
- package/dist/modules/ABTest.js +113 -0
- package/dist/modules/Analytics.d.ts +91 -0
- package/dist/modules/Analytics.js +182 -0
- package/dist/modules/Survey.d.ts +65 -0
- package/dist/modules/Survey.js +82 -0
- package/dist/modules/VirtualCurrency.d.ts +63 -0
- package/dist/modules/VirtualCurrency.js +147 -0
- package/dist/murmur.d.ts +23 -0
- package/dist/murmur.js +104 -0
- package/dist/notifications/LiveActivitiesManager.d.ts +47 -0
- package/dist/notifications/LiveActivitiesManager.js +106 -0
- package/dist/notifications/NotificationScheduler.d.ts +55 -0
- package/dist/notifications/NotificationScheduler.js +199 -0
- package/dist/notifications/PurchaseNotificationHandler.d.ts +24 -0
- package/dist/notifications/PurchaseNotificationHandler.js +55 -0
- package/dist/notifications/useDeviceToken.d.ts +36 -0
- package/dist/notifications/useDeviceToken.js +97 -0
- package/dist/notifications/useLiveActivity.d.ts +39 -0
- package/dist/notifications/useLiveActivity.js +104 -0
- package/dist/review/ReviewAnalytics.d.ts +34 -0
- package/dist/review/ReviewAnalytics.js +73 -0
- package/dist/review/ReviewManager.d.ts +83 -0
- package/dist/review/ReviewManager.js +339 -0
- package/dist/review/ReviewTimingManager.d.ts +82 -0
- package/dist/review/ReviewTimingManager.js +224 -0
- package/dist/survey-core/types.d.ts +215 -0
- package/dist/survey-core/types.js +8 -0
- package/dist/types.d.ts +438 -0
- package/dist/types.js +158 -0
- package/dist/utils/ApiClient.d.ts +65 -0
- package/dist/utils/ApiClient.js +132 -0
- package/dist/utils/CSSConverter.d.ts +49 -0
- package/dist/utils/CSSConverter.js +470 -0
- package/dist/utils/animations.d.ts +41 -0
- package/dist/utils/animations.js +194 -0
- package/dist/utils/calendarIntegration.d.ts +36 -0
- package/dist/utils/calendarIntegration.js +89 -0
- package/dist/utils/configurationResolver.d.ts +23 -0
- package/dist/utils/configurationResolver.js +78 -0
- package/dist/utils/deviceDetection.d.ts +38 -0
- package/dist/utils/deviceDetection.js +59 -0
- package/dist/utils/hapticFeedback.d.ts +17 -0
- package/dist/utils/hapticFeedback.js +53 -0
- package/dist/utils/iconMapper.d.ts +26 -0
- package/dist/utils/iconMapper.js +113 -0
- package/dist/utils/notificationPermissions.d.ts +13 -0
- package/dist/utils/notificationPermissions.js +51 -0
- package/dist/utils/priceFormatting.d.ts +19 -0
- package/dist/utils/priceFormatting.js +99 -0
- package/dist/utils/shareSheet.d.ts +17 -0
- package/dist/utils/shareSheet.js +42 -0
- package/dist/utils/subscriptionUpgrade.d.ts +84 -0
- package/dist/utils/subscriptionUpgrade.js +100 -0
- package/dist/valueUtils.d.ts +48 -0
- package/dist/valueUtils.js +129 -0
- package/dist/xFlowTags.d.ts +18 -0
- package/dist/xFlowTags.js +385 -0
- package/ios/BillDogABTest.m +50 -0
- package/ios/BillDogABTest.swift +188 -0
- package/ios/BillDogAnalytics.m +105 -0
- package/ios/BillDogAnalytics.swift +324 -0
- package/ios/BillDogBridge.m +222 -0
- package/ios/BillDogBridge.swift +715 -0
- package/ios/BillDogLiveActivities.m +41 -0
- package/ios/BillDogLiveActivities.swift +104 -0
- package/ios/BillDogPaywallViewManager.m +39 -0
- package/ios/BillDogPaywallViewManager.swift +361 -0
- package/ios/BillDogSurvey.m +34 -0
- package/ios/BillDogSurvey.swift +257 -0
- package/ios/BillDogVirtualCurrencyBridge.m +63 -0
- package/ios/BillDogVirtualCurrencyBridge.swift +511 -0
- package/junit.xml +25 -0
- package/package.json +61 -0
- package/react-native.config.js +13 -0
- package/src/AdvancedPaywallCache.ts +433 -0
- package/src/BillDog.ts +983 -0
- package/src/BillDogConfiguration.ts +318 -0
- package/src/ComponentRenderer.tsx +1325 -0
- package/src/LayoutEngine.ts +459 -0
- package/src/LocalizationResolver.ts +311 -0
- package/src/NativePaywallView.tsx +132 -0
- package/src/PaywallCache.ts +358 -0
- package/src/PaywallStateManager.ts +154 -0
- package/src/PaywallView.tsx +328 -0
- package/src/ProductVariableProvider.ts +282 -0
- package/src/VariableResolver.ts +516 -0
- package/src/WebViewPaywall.tsx +454 -0
- package/src/animations/presets.ts +421 -0
- package/src/components/AccoladeCpsComponent.tsx +259 -0
- package/src/components/AccordionComponent.tsx +213 -0
- package/src/components/AnimatedWrapper.tsx +316 -0
- package/src/components/CarouselComponent.tsx +615 -0
- package/src/components/ChartCurveComponent.tsx +452 -0
- package/src/components/CheckboxComponent.tsx +185 -0
- package/src/components/ConfettiComponent.tsx +178 -0
- package/src/components/CountdownComponent.tsx +454 -0
- package/src/components/DelayedXComponent.tsx +266 -0
- package/src/components/DrawerModalComponent.tsx +324 -0
- package/src/components/GradientView.tsx +129 -0
- package/src/components/HapticFeedbackComponent.tsx +39 -0
- package/src/components/HorizontalProductsComponent.tsx +329 -0
- package/src/components/MultiChoiceGridComponent.tsx +265 -0
- package/src/components/NPSScaleComponent.tsx +294 -0
- package/src/components/NavigationComponent.tsx +329 -0
- package/src/components/OAuthButtonComponent.tsx +266 -0
- package/src/components/ProgressLoaderComponent.tsx +366 -0
- package/src/components/ProgressStepperComponent.tsx +250 -0
- package/src/components/SegmentedPickerComponent.tsx +245 -0
- package/src/components/ShareButtonsComponent.tsx +299 -0
- package/src/components/ShareCodeComponent.tsx +303 -0
- package/src/components/SingleChoiceGridComponent.tsx +229 -0
- package/src/components/SliderComponent.tsx +280 -0
- package/src/components/StarRatingInputComponent.tsx +223 -0
- package/src/components/StickerCompositeComponent.tsx +168 -0
- package/src/components/TabsComponent.tsx +496 -0
- package/src/components/TextInputComponent.tsx +258 -0
- package/src/components/TimelineComponent.tsx +129 -0
- package/src/components/ToggleComponent.tsx +142 -0
- package/src/components/VerticalProductsComponent.tsx +357 -0
- package/src/dynamicValues.ts +180 -0
- package/src/filters/dateFilters.ts +411 -0
- package/src/filters/index.ts +281 -0
- package/src/hooks/useOfferings.ts +192 -0
- package/src/hooks/usePaywall.ts +154 -0
- package/src/hooks/usePlacement.ts +143 -0
- package/src/hooks/useSubscription.ts +154 -0
- package/src/index.ts +245 -0
- package/src/models/BillDogError.ts +24 -0
- package/src/models/CacheFetchPolicy.ts +13 -0
- package/src/models/CustomProduct.ts +33 -0
- package/src/models/CustomerInfo.ts +26 -0
- package/src/models/Delegate.ts +22 -0
- package/src/models/EntitlementInfo.ts +27 -0
- package/src/models/Placement.ts +50 -0
- package/src/models/PurchaseParams.ts +81 -0
- package/src/models/PurchaseResult.ts +32 -0
- package/src/models/RestoreResult.ts +27 -0
- package/src/models/RestoredItem.ts +25 -0
- package/src/modules/ABTest.ts +131 -0
- package/src/modules/Analytics.ts +227 -0
- package/src/modules/Survey.ts +126 -0
- package/src/modules/VirtualCurrency.ts +223 -0
- package/src/murmur.ts +102 -0
- package/src/notifications/LiveActivitiesManager.ts +140 -0
- package/src/notifications/NotificationScheduler.ts +292 -0
- package/src/notifications/PurchaseNotificationHandler.ts +67 -0
- package/src/notifications/useDeviceToken.ts +116 -0
- package/src/notifications/useLiveActivity.ts +125 -0
- package/src/review/ReviewAnalytics.ts +89 -0
- package/src/review/ReviewManager.ts +355 -0
- package/src/review/ReviewTimingManager.ts +265 -0
- package/src/survey-core/types.ts +244 -0
- package/src/types/ambient.d.ts +9 -0
- package/src/types.ts +680 -0
- package/src/utils/ApiClient.ts +163 -0
- package/src/utils/CSSConverter.ts +552 -0
- package/src/utils/animations.ts +232 -0
- package/src/utils/calendarIntegration.ts +113 -0
- package/src/utils/configurationResolver.ts +106 -0
- package/src/utils/deviceDetection.ts +83 -0
- package/src/utils/hapticFeedback.ts +55 -0
- package/src/utils/iconMapper.ts +102 -0
- package/src/utils/notificationPermissions.ts +48 -0
- package/src/utils/priceFormatting.ts +119 -0
- package/src/utils/shareSheet.ts +55 -0
- package/src/utils/subscriptionUpgrade.ts +183 -0
- package/src/valueUtils.ts +108 -0
- package/src/xFlowTags.ts +463 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PaywallCache - Smart caching layer for React Native
|
|
4
|
+
* Uses AsyncStorage for metadata and RNFS for asset caching
|
|
5
|
+
* Supports server-provided cache configuration
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.PaywallCache = exports.DEFAULT_CACHE_CONFIG = void 0;
|
|
12
|
+
const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
|
|
13
|
+
const react_native_fs_1 = __importDefault(require("react-native-fs"));
|
|
14
|
+
exports.DEFAULT_CACHE_CONFIG = {
|
|
15
|
+
enabled: true,
|
|
16
|
+
maxCacheAge: 604800000, // 7 days
|
|
17
|
+
backgroundUpdateEnabled: true,
|
|
18
|
+
preloadAssets: true,
|
|
19
|
+
};
|
|
20
|
+
// Track background updates in progress
|
|
21
|
+
const backgroundUpdateInProgress = new Set();
|
|
22
|
+
class PaywallCache {
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
this.fallbackCache = new Map();
|
|
25
|
+
this.config = { ...exports.DEFAULT_CACHE_CONFIG, ...config };
|
|
26
|
+
this.cacheDir = `${react_native_fs_1.default.CachesDirectoryPath}/billdog_paywalls`;
|
|
27
|
+
// Create cache directory
|
|
28
|
+
react_native_fs_1.default.mkdir(this.cacheDir).catch(() => {
|
|
29
|
+
// Directory might already exist
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// MARK: - Configuration
|
|
33
|
+
/**
|
|
34
|
+
* Update cache configuration from server response
|
|
35
|
+
*/
|
|
36
|
+
configureFromServer(serverConfig) {
|
|
37
|
+
this.config = { ...this.config, ...serverConfig };
|
|
38
|
+
console.log('[PaywallCache] Configured from server:', this.config);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get current cache configuration
|
|
42
|
+
*/
|
|
43
|
+
getConfig() {
|
|
44
|
+
return { ...this.config };
|
|
45
|
+
}
|
|
46
|
+
// MARK: - Paywall Caching
|
|
47
|
+
async get(identifier) {
|
|
48
|
+
if (!this.config.enabled) {
|
|
49
|
+
// Still return fallback if available
|
|
50
|
+
return this.fallbackCache.get(identifier) || null;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const key = `paywall:${identifier}`;
|
|
54
|
+
const cachedJson = await async_storage_1.default.getItem(key);
|
|
55
|
+
if (!cachedJson) {
|
|
56
|
+
console.log(`[PaywallCache] MISS: ${identifier}`);
|
|
57
|
+
// Return fallback if available
|
|
58
|
+
return this.fallbackCache.get(identifier) || null;
|
|
59
|
+
}
|
|
60
|
+
const cached = JSON.parse(cachedJson);
|
|
61
|
+
// Check expiration (unless it's a fallback)
|
|
62
|
+
if (!cached.isFallback && Date.now() > cached.expiresAt) {
|
|
63
|
+
console.log(`[PaywallCache] EXPIRED: ${identifier}`);
|
|
64
|
+
await this.delete(identifier);
|
|
65
|
+
// Return fallback if available
|
|
66
|
+
return this.fallbackCache.get(identifier) || null;
|
|
67
|
+
}
|
|
68
|
+
console.log(`[PaywallCache] HIT: ${identifier} (v${cached.version})${cached.isFallback ? ' (fallback)' : ''}`);
|
|
69
|
+
return cached;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error(`[PaywallCache] ERROR reading cache:`, error);
|
|
73
|
+
return this.fallbackCache.get(identifier) || null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async set(identifier, paywall) {
|
|
77
|
+
if (!this.config.enabled && !paywall.isFallback)
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
// Calculate expiration using server-provided maxCacheAge
|
|
81
|
+
const cacheEntry = {
|
|
82
|
+
...paywall,
|
|
83
|
+
cachedAt: Date.now(),
|
|
84
|
+
expiresAt: Date.now() + this.config.maxCacheAge,
|
|
85
|
+
};
|
|
86
|
+
const key = `paywall:${identifier}`;
|
|
87
|
+
const cachedJson = JSON.stringify(cacheEntry);
|
|
88
|
+
await async_storage_1.default.setItem(key, cachedJson);
|
|
89
|
+
console.log(`[PaywallCache] CACHED: ${identifier} (v${paywall.version}) TTL: ${this.config.maxCacheAge / 1000}s`);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error(`[PaywallCache] ERROR writing cache:`, error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Set a fallback paywall that will never be cleared
|
|
97
|
+
*/
|
|
98
|
+
async setFallback(identifier, paywall) {
|
|
99
|
+
const fallbackPaywall = {
|
|
100
|
+
...paywall,
|
|
101
|
+
isFallback: true,
|
|
102
|
+
expiresAt: Date.now() + (365 * 24 * 60 * 60 * 1000), // 1 year
|
|
103
|
+
};
|
|
104
|
+
// Store in memory for fast access
|
|
105
|
+
this.fallbackCache.set(identifier, fallbackPaywall);
|
|
106
|
+
// Also persist to storage
|
|
107
|
+
await this.set(identifier, fallbackPaywall);
|
|
108
|
+
console.log(`[PaywallCache] FALLBACK SET: ${identifier}`);
|
|
109
|
+
}
|
|
110
|
+
async delete(identifier, includeFallback = false) {
|
|
111
|
+
try {
|
|
112
|
+
// Check if it's a fallback and skip if not forcing
|
|
113
|
+
if (!includeFallback) {
|
|
114
|
+
const key = `paywall:${identifier}`;
|
|
115
|
+
const cachedJson = await async_storage_1.default.getItem(key);
|
|
116
|
+
if (cachedJson) {
|
|
117
|
+
const cached = JSON.parse(cachedJson);
|
|
118
|
+
if (cached.isFallback) {
|
|
119
|
+
console.log(`[PaywallCache] SKIP DELETE FALLBACK: ${identifier}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const key = `paywall:${identifier}`;
|
|
125
|
+
await async_storage_1.default.removeItem(key);
|
|
126
|
+
if (includeFallback) {
|
|
127
|
+
this.fallbackCache.delete(identifier);
|
|
128
|
+
}
|
|
129
|
+
console.log(`[PaywallCache] DELETED: ${identifier}`);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error(`[PaywallCache] ERROR deleting cache:`, error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// MARK: - Background Updates
|
|
136
|
+
/**
|
|
137
|
+
* Check if background update is needed and trigger if enabled
|
|
138
|
+
*/
|
|
139
|
+
shouldTriggerBackgroundUpdate(identifier) {
|
|
140
|
+
if (!this.config.backgroundUpdateEnabled)
|
|
141
|
+
return false;
|
|
142
|
+
if (backgroundUpdateInProgress.has(identifier))
|
|
143
|
+
return false;
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
markBackgroundUpdateStarted(identifier) {
|
|
147
|
+
backgroundUpdateInProgress.add(identifier);
|
|
148
|
+
}
|
|
149
|
+
markBackgroundUpdateCompleted(identifier) {
|
|
150
|
+
backgroundUpdateInProgress.delete(identifier);
|
|
151
|
+
}
|
|
152
|
+
// MARK: - Asset Caching
|
|
153
|
+
async cacheAsset(url) {
|
|
154
|
+
if (!this.config.preloadAssets)
|
|
155
|
+
return null;
|
|
156
|
+
try {
|
|
157
|
+
const fileName = url.split('/').pop() || 'asset';
|
|
158
|
+
const localPath = `${this.cacheDir}/${fileName}`;
|
|
159
|
+
// Check if already cached
|
|
160
|
+
const exists = await react_native_fs_1.default.exists(localPath);
|
|
161
|
+
if (exists) {
|
|
162
|
+
console.log(`[PaywallCache] Asset already cached: ${fileName}`);
|
|
163
|
+
return localPath;
|
|
164
|
+
}
|
|
165
|
+
// Download and cache
|
|
166
|
+
const result = await react_native_fs_1.default.downloadFile({
|
|
167
|
+
fromUrl: url,
|
|
168
|
+
toFile: localPath,
|
|
169
|
+
}).promise;
|
|
170
|
+
if (result.statusCode === 200) {
|
|
171
|
+
console.log(`[PaywallCache] Asset cached: ${fileName}`);
|
|
172
|
+
return localPath;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.error(`[PaywallCache] Asset download failed: ${result.statusCode}`);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
console.error(`[PaywallCache] Asset caching error:`, error);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Preload all assets from a paywall configuration
|
|
186
|
+
*/
|
|
187
|
+
async preloadPaywallAssets(configuration) {
|
|
188
|
+
if (!this.config.preloadAssets)
|
|
189
|
+
return;
|
|
190
|
+
const assetUrls = this.extractAssetUrls(configuration);
|
|
191
|
+
console.log(`[PaywallCache] Preloading ${assetUrls.length} assets`);
|
|
192
|
+
await Promise.all(assetUrls.map(url => this.cacheAsset(url)));
|
|
193
|
+
}
|
|
194
|
+
extractAssetUrls(config) {
|
|
195
|
+
const urls = [];
|
|
196
|
+
const traverse = (obj) => {
|
|
197
|
+
if (!obj || typeof obj !== 'object')
|
|
198
|
+
return;
|
|
199
|
+
if (typeof obj.src === 'string' && obj.src.startsWith('http')) {
|
|
200
|
+
urls.push(obj.src);
|
|
201
|
+
}
|
|
202
|
+
if (typeof obj.imageUrl === 'string' && obj.imageUrl.startsWith('http')) {
|
|
203
|
+
urls.push(obj.imageUrl);
|
|
204
|
+
}
|
|
205
|
+
if (typeof obj.backgroundImage === 'string' && obj.backgroundImage.startsWith('http')) {
|
|
206
|
+
urls.push(obj.backgroundImage);
|
|
207
|
+
}
|
|
208
|
+
Object.values(obj).forEach(traverse);
|
|
209
|
+
};
|
|
210
|
+
traverse(config);
|
|
211
|
+
return [...new Set(urls)]; // Remove duplicates
|
|
212
|
+
}
|
|
213
|
+
async getCachedAssetPath(url) {
|
|
214
|
+
try {
|
|
215
|
+
const fileName = url.split('/').pop() || 'asset';
|
|
216
|
+
const localPath = `${this.cacheDir}/${fileName}`;
|
|
217
|
+
const exists = await react_native_fs_1.default.exists(localPath);
|
|
218
|
+
return exists ? localPath : null;
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
console.error(`[PaywallCache] Error checking cached asset:`, error);
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// MARK: - Cache Management
|
|
226
|
+
/**
|
|
227
|
+
* Clear regular cache (preserves fallbacks)
|
|
228
|
+
*/
|
|
229
|
+
async clearAll() {
|
|
230
|
+
try {
|
|
231
|
+
// Clear AsyncStorage keys (skip fallbacks)
|
|
232
|
+
const keys = await async_storage_1.default.getAllKeys();
|
|
233
|
+
const paywallKeys = keys.filter((key) => key.startsWith('paywall:'));
|
|
234
|
+
for (const key of paywallKeys) {
|
|
235
|
+
const cachedJson = await async_storage_1.default.getItem(key);
|
|
236
|
+
if (cachedJson) {
|
|
237
|
+
const cached = JSON.parse(cachedJson);
|
|
238
|
+
if (!cached.isFallback) {
|
|
239
|
+
await async_storage_1.default.removeItem(key);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// Clear file cache
|
|
244
|
+
const files = await react_native_fs_1.default.readDir(this.cacheDir);
|
|
245
|
+
await Promise.all(files.map((file) => react_native_fs_1.default.unlink(file.path)));
|
|
246
|
+
console.log('[PaywallCache] Cache cleared (fallbacks preserved)');
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
console.error('[PaywallCache] Error clearing cache:', error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Clear all cache including fallbacks
|
|
254
|
+
*/
|
|
255
|
+
async clearAllIncludingFallbacks() {
|
|
256
|
+
try {
|
|
257
|
+
const keys = await async_storage_1.default.getAllKeys();
|
|
258
|
+
const paywallKeys = keys.filter((key) => key.startsWith('paywall:'));
|
|
259
|
+
await async_storage_1.default.multiRemove(paywallKeys);
|
|
260
|
+
const files = await react_native_fs_1.default.readDir(this.cacheDir);
|
|
261
|
+
await Promise.all(files.map((file) => react_native_fs_1.default.unlink(file.path)));
|
|
262
|
+
this.fallbackCache.clear();
|
|
263
|
+
console.log('[PaywallCache] All cache cleared including fallbacks');
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
console.error('[PaywallCache] Error clearing cache:', error);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async getStats() {
|
|
270
|
+
try {
|
|
271
|
+
const keys = await async_storage_1.default.getAllKeys();
|
|
272
|
+
const paywallKeys = keys.filter((key) => key.startsWith('paywall:'));
|
|
273
|
+
const files = await react_native_fs_1.default.readDir(this.cacheDir);
|
|
274
|
+
const assetCount = files.length;
|
|
275
|
+
return {
|
|
276
|
+
paywallCount: paywallKeys.length,
|
|
277
|
+
assetCount,
|
|
278
|
+
fallbackCount: this.fallbackCache.size,
|
|
279
|
+
config: this.config,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
console.error('[PaywallCache] Error getting stats:', error);
|
|
284
|
+
return {
|
|
285
|
+
paywallCount: 0,
|
|
286
|
+
assetCount: 0,
|
|
287
|
+
fallbackCount: 0,
|
|
288
|
+
config: this.config,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
exports.PaywallCache = PaywallCache;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type StateListener = (value: any) => void;
|
|
2
|
+
export type Unsubscribe = () => void;
|
|
3
|
+
export declare class PaywallStateManager {
|
|
4
|
+
/**
|
|
5
|
+
* Paywall-wide key holding the live product selection.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately NOT `element:{id}.selectedIndex` — that form is scoped to a single
|
|
8
|
+
* products component, while Dynamic Values need one well-known key to react to. The
|
|
9
|
+
* name matches the variable key the DV bag emits (`products.selectedIndex`), so an
|
|
10
|
+
* authored condition and the state driving it are spelled identically.
|
|
11
|
+
*
|
|
12
|
+
* Parity: Android `PaywallStateManager.SELECTED_INDEX_KEY`, iOS
|
|
13
|
+
* `PaywallView.selectedIndexStateKey`.
|
|
14
|
+
*/
|
|
15
|
+
static readonly SELECTED_INDEX_KEY = "products.selectedIndex";
|
|
16
|
+
/** Shared instance. Native uses a singleton (Kotlin `object` / Swift `.shared`); the
|
|
17
|
+
* class stays exported so tests can build an isolated store. */
|
|
18
|
+
static readonly shared: PaywallStateManager;
|
|
19
|
+
private state;
|
|
20
|
+
private listeners;
|
|
21
|
+
/** Read the current value, or `defaultValue` when unset. */
|
|
22
|
+
getState<T = any>(key: string, defaultValue?: T): T | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Write a value and notify subscribers.
|
|
25
|
+
*
|
|
26
|
+
* The structural-equality guard is load-bearing, not an optimisation: components
|
|
27
|
+
* write their state in an effect keyed on that same state, so an unconditional
|
|
28
|
+
* notify would loop (write → notify → setState → effect → write). Android relies on
|
|
29
|
+
* the identical guard.
|
|
30
|
+
*/
|
|
31
|
+
setState(key: string, value: any): void;
|
|
32
|
+
/** Alias for {@link setState} — the name 53 existing call sites use (web-builder parity). */
|
|
33
|
+
updateState(key: string, value: any): void;
|
|
34
|
+
/** Alias for {@link getState} — used by the component test suite. */
|
|
35
|
+
getValue<T = any>(key: string, defaultValue?: T): T | undefined;
|
|
36
|
+
/** Alias for {@link setState} — used by the component test suite. */
|
|
37
|
+
setValue(key: string, value: any): void;
|
|
38
|
+
/**
|
|
39
|
+
* Subscribe to a key. Returns an unsubscribe function — components return it
|
|
40
|
+
* directly from `useEffect`, so it MUST be callable and idempotent.
|
|
41
|
+
*/
|
|
42
|
+
subscribe(key: string, listener: StateListener): Unsubscribe;
|
|
43
|
+
/** Alias for {@link subscribe} — the name 14 existing call sites use. */
|
|
44
|
+
subscribeToState(key: string, listener: StateListener): Unsubscribe;
|
|
45
|
+
/**
|
|
46
|
+
* Clear all state AND subscriptions, for a fresh paywall presentation.
|
|
47
|
+
*
|
|
48
|
+
* ORDERING TRAP (React-specific, inverted from the native SDKs): child effects run
|
|
49
|
+
* BEFORE parent effects, so calling this from a mount effect in PaywallView would
|
|
50
|
+
* wipe the subscriptions its children registered moments earlier, leaving every
|
|
51
|
+
* component permanently deaf. PaywallView therefore resets during its first render —
|
|
52
|
+
* before any child mounts. See the ref-guarded reset there.
|
|
53
|
+
*/
|
|
54
|
+
clearAll(): void;
|
|
55
|
+
/** Clear state for one component (`element:{componentId}.*`). */
|
|
56
|
+
clearComponent(componentId: string): void;
|
|
57
|
+
/** Snapshot of all state (debugging / diagnostics). */
|
|
58
|
+
getAllState(): Record<string, any>;
|
|
59
|
+
private notify;
|
|
60
|
+
}
|
|
61
|
+
/** Shared instance — the one PaywallView threads through the component tree. */
|
|
62
|
+
export declare const paywallStateManager: PaywallStateManager;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.paywallStateManager = exports.PaywallStateManager = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* PaywallStateManager — element state for React Native paywall components.
|
|
6
|
+
*
|
|
7
|
+
* Parity with `io.billdog.compose.ui.PaywallStateManager` (Android) and
|
|
8
|
+
* `PaywallStateManager.shared` (iOS): a key→value store with per-key subscriptions,
|
|
9
|
+
* following the `element:{componentId}.{property}` convention, plus the paywall-wide
|
|
10
|
+
* `products.selectedIndex` key that drives selection-reactive Dynamic Values.
|
|
11
|
+
*
|
|
12
|
+
* WHY THIS EXISTS: 27 RN component files already called a `stateManager` prop
|
|
13
|
+
* (`updateState`, `subscribeToState`, `getState`, `setState`, `subscribe`) — but
|
|
14
|
+
* nothing ever PROVIDED one, and every call site optional-chains
|
|
15
|
+
* (`stateManager?.updateState?.(...)`). So the entire cross-component state protocol
|
|
16
|
+
* was dead code that failed silently: toggles could not drive visibility, tabs could
|
|
17
|
+
* not be driven externally, and product selection was invisible outside the products
|
|
18
|
+
* component. This is the missing implementation, not a new abstraction.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* PaywallStateManager.shared.setState('element:slider_1.currentValue', 75);
|
|
22
|
+
* const v = PaywallStateManager.shared.getState<number>('element:slider_1.currentValue');
|
|
23
|
+
*/
|
|
24
|
+
const valueUtils_1 = require("./valueUtils");
|
|
25
|
+
class PaywallStateManager {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.state = new Map();
|
|
28
|
+
this.listeners = new Map();
|
|
29
|
+
}
|
|
30
|
+
/** Read the current value, or `defaultValue` when unset. */
|
|
31
|
+
getState(key, defaultValue) {
|
|
32
|
+
const v = this.state.get(key);
|
|
33
|
+
return v === undefined ? defaultValue : v;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Write a value and notify subscribers.
|
|
37
|
+
*
|
|
38
|
+
* The structural-equality guard is load-bearing, not an optimisation: components
|
|
39
|
+
* write their state in an effect keyed on that same state, so an unconditional
|
|
40
|
+
* notify would loop (write → notify → setState → effect → write). Android relies on
|
|
41
|
+
* the identical guard.
|
|
42
|
+
*/
|
|
43
|
+
setState(key, value) {
|
|
44
|
+
if (this.state.has(key) && (0, valueUtils_1.isDeepEqual)(this.state.get(key), value))
|
|
45
|
+
return;
|
|
46
|
+
this.state.set(key, value);
|
|
47
|
+
this.notify(key, value);
|
|
48
|
+
}
|
|
49
|
+
/** Alias for {@link setState} — the name 53 existing call sites use (web-builder parity). */
|
|
50
|
+
updateState(key, value) {
|
|
51
|
+
this.setState(key, value);
|
|
52
|
+
}
|
|
53
|
+
/** Alias for {@link getState} — used by the component test suite. */
|
|
54
|
+
getValue(key, defaultValue) {
|
|
55
|
+
return this.getState(key, defaultValue);
|
|
56
|
+
}
|
|
57
|
+
/** Alias for {@link setState} — used by the component test suite. */
|
|
58
|
+
setValue(key, value) {
|
|
59
|
+
this.setState(key, value);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Subscribe to a key. Returns an unsubscribe function — components return it
|
|
63
|
+
* directly from `useEffect`, so it MUST be callable and idempotent.
|
|
64
|
+
*/
|
|
65
|
+
subscribe(key, listener) {
|
|
66
|
+
let set = this.listeners.get(key);
|
|
67
|
+
if (!set) {
|
|
68
|
+
set = new Set();
|
|
69
|
+
this.listeners.set(key, set);
|
|
70
|
+
}
|
|
71
|
+
set.add(listener);
|
|
72
|
+
return () => {
|
|
73
|
+
const current = this.listeners.get(key);
|
|
74
|
+
if (!current)
|
|
75
|
+
return;
|
|
76
|
+
current.delete(listener);
|
|
77
|
+
if (current.size === 0)
|
|
78
|
+
this.listeners.delete(key);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Alias for {@link subscribe} — the name 14 existing call sites use. */
|
|
82
|
+
subscribeToState(key, listener) {
|
|
83
|
+
return this.subscribe(key, listener);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear all state AND subscriptions, for a fresh paywall presentation.
|
|
87
|
+
*
|
|
88
|
+
* ORDERING TRAP (React-specific, inverted from the native SDKs): child effects run
|
|
89
|
+
* BEFORE parent effects, so calling this from a mount effect in PaywallView would
|
|
90
|
+
* wipe the subscriptions its children registered moments earlier, leaving every
|
|
91
|
+
* component permanently deaf. PaywallView therefore resets during its first render —
|
|
92
|
+
* before any child mounts. See the ref-guarded reset there.
|
|
93
|
+
*/
|
|
94
|
+
clearAll() {
|
|
95
|
+
this.state.clear();
|
|
96
|
+
this.listeners.clear();
|
|
97
|
+
}
|
|
98
|
+
/** Clear state for one component (`element:{componentId}.*`). */
|
|
99
|
+
clearComponent(componentId) {
|
|
100
|
+
const prefix = `element:${componentId}.`;
|
|
101
|
+
for (const key of Array.from(this.state.keys())) {
|
|
102
|
+
if (key.startsWith(prefix)) {
|
|
103
|
+
this.state.delete(key);
|
|
104
|
+
this.listeners.delete(key);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Snapshot of all state (debugging / diagnostics). */
|
|
109
|
+
getAllState() {
|
|
110
|
+
return Object.fromEntries(this.state);
|
|
111
|
+
}
|
|
112
|
+
notify(key, value) {
|
|
113
|
+
const set = this.listeners.get(key);
|
|
114
|
+
if (!set)
|
|
115
|
+
return;
|
|
116
|
+
// Copy before iterating: a listener may unsubscribe (or subscribe) while running,
|
|
117
|
+
// which would otherwise mutate the Set mid-iteration.
|
|
118
|
+
for (const listener of Array.from(set)) {
|
|
119
|
+
try {
|
|
120
|
+
listener(value);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
// One misbehaving component must not take down the paywall render or starve
|
|
124
|
+
// the remaining listeners of this update.
|
|
125
|
+
console.warn(`[BillDog] state listener for "${key}" threw:`, err);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.PaywallStateManager = PaywallStateManager;
|
|
131
|
+
/**
|
|
132
|
+
* Paywall-wide key holding the live product selection.
|
|
133
|
+
*
|
|
134
|
+
* Deliberately NOT `element:{id}.selectedIndex` — that form is scoped to a single
|
|
135
|
+
* products component, while Dynamic Values need one well-known key to react to. The
|
|
136
|
+
* name matches the variable key the DV bag emits (`products.selectedIndex`), so an
|
|
137
|
+
* authored condition and the state driving it are spelled identically.
|
|
138
|
+
*
|
|
139
|
+
* Parity: Android `PaywallStateManager.SELECTED_INDEX_KEY`, iOS
|
|
140
|
+
* `PaywallView.selectedIndexStateKey`.
|
|
141
|
+
*/
|
|
142
|
+
PaywallStateManager.SELECTED_INDEX_KEY = 'products.selectedIndex';
|
|
143
|
+
/** Shared instance. Native uses a singleton (Kotlin `object` / Swift `.shared`); the
|
|
144
|
+
* class stays exported so tests can build an isolated store. */
|
|
145
|
+
PaywallStateManager.shared = new PaywallStateManager();
|
|
146
|
+
/** Shared instance — the one PaywallView threads through the component tree. */
|
|
147
|
+
exports.paywallStateManager = PaywallStateManager.shared;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PaywallView - Main React Native component for rendering paywalls
|
|
3
|
+
*
|
|
4
|
+
* Credentials and API base URL are resolved from BillDogConfiguration.
|
|
5
|
+
* Pass an `apiKey` prop only for backward compatibility.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { PaywallConfiguration } from './types';
|
|
9
|
+
interface PaywallViewProps {
|
|
10
|
+
/**
|
|
11
|
+
* Paywall identifier to fetch from API
|
|
12
|
+
*/
|
|
13
|
+
paywallIdentifier?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Direct configuration (skips API fetch)
|
|
16
|
+
*/
|
|
17
|
+
configuration?: PaywallConfiguration;
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Use BillDogConfiguration.configure({ apiKey }) instead
|
|
20
|
+
*/
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Called when user interacts with buttons
|
|
24
|
+
*/
|
|
25
|
+
onButtonPress?: (componentId: string, action: string) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Called when paywall is dismissed
|
|
28
|
+
*/
|
|
29
|
+
onDismiss?: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Loading component (optional)
|
|
32
|
+
*/
|
|
33
|
+
LoadingComponent?: React.ComponentType;
|
|
34
|
+
/**
|
|
35
|
+
* Error component (optional)
|
|
36
|
+
*/
|
|
37
|
+
ErrorComponent?: React.ComponentType<{
|
|
38
|
+
error: Error;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
export declare const PaywallView: React.FC<PaywallViewProps>;
|
|
42
|
+
export {};
|