@virex-tech/paywallo-sdk 2.1.0 → 2.2.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.
- package/dist/index.d.mts +121 -7
- package/dist/index.d.ts +121 -7
- package/dist/index.js +1146 -605
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1131 -596
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloDevice.swift +29 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -212,6 +212,9 @@ function isAvailable() {
|
|
|
212
212
|
function clearCache() {
|
|
213
213
|
cachedDeviceInfo = null;
|
|
214
214
|
}
|
|
215
|
+
function getCachedDeviceInfo() {
|
|
216
|
+
return cachedDeviceInfo;
|
|
217
|
+
}
|
|
215
218
|
var import_react_native, FALLBACK, _debug, warnedOnce, cachedDeviceInfo, nativeDeviceInfo;
|
|
216
219
|
var init_NativeDeviceInfo = __esm({
|
|
217
220
|
"src/utils/NativeDeviceInfo.ts"() {
|
|
@@ -239,6 +242,7 @@ var init_NativeDeviceInfo = __esm({
|
|
|
239
242
|
cachedDeviceInfo = null;
|
|
240
243
|
nativeDeviceInfo = {
|
|
241
244
|
getDeviceInfo,
|
|
245
|
+
getCachedDeviceInfo,
|
|
242
246
|
getInstallReferrer,
|
|
243
247
|
isAvailable,
|
|
244
248
|
clearCache
|
|
@@ -499,7 +503,7 @@ var init_IdentityStorage = __esm({
|
|
|
499
503
|
});
|
|
500
504
|
|
|
501
505
|
// src/domains/identity/IdentityManager.ts
|
|
502
|
-
var EMAIL_REGEX, IdentityManager, identityManager;
|
|
506
|
+
var USER_PHONE_KEY, USER_FIRST_NAME_KEY, USER_LAST_NAME_KEY, USER_DOB_KEY, USER_GENDER_KEY, EMAIL_REGEX, IdentityManager, identityManager;
|
|
503
507
|
var init_IdentityManager = __esm({
|
|
504
508
|
"src/domains/identity/IdentityManager.ts"() {
|
|
505
509
|
"use strict";
|
|
@@ -509,6 +513,11 @@ var init_IdentityManager = __esm({
|
|
|
509
513
|
init_SecureStorage();
|
|
510
514
|
init_StorageMigration();
|
|
511
515
|
init_IdentityStorage();
|
|
516
|
+
USER_PHONE_KEY = "@panel:user_phone";
|
|
517
|
+
USER_FIRST_NAME_KEY = "@panel:user_first_name";
|
|
518
|
+
USER_LAST_NAME_KEY = "@panel:user_last_name";
|
|
519
|
+
USER_DOB_KEY = "@panel:user_dob";
|
|
520
|
+
USER_GENDER_KEY = "@panel:user_gender";
|
|
512
521
|
EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
513
522
|
IdentityManager = class {
|
|
514
523
|
constructor() {
|
|
@@ -516,6 +525,11 @@ var init_IdentityManager = __esm({
|
|
|
516
525
|
this.anonId = null;
|
|
517
526
|
this.email = null;
|
|
518
527
|
this.properties = {};
|
|
528
|
+
this.phone = null;
|
|
529
|
+
this.firstName = null;
|
|
530
|
+
this.lastName = null;
|
|
531
|
+
this.dateOfBirth = null;
|
|
532
|
+
this.gender = null;
|
|
519
533
|
this.apiClient = null;
|
|
520
534
|
this.secureStorage = null;
|
|
521
535
|
this.debug = false;
|
|
@@ -571,7 +585,7 @@ var init_IdentityManager = __esm({
|
|
|
571
585
|
let email;
|
|
572
586
|
let properties;
|
|
573
587
|
if (options) {
|
|
574
|
-
if ("email" in options || "properties" in options) {
|
|
588
|
+
if ("email" in options || "properties" in options || "phone" in options || "firstName" in options || "lastName" in options || "dateOfBirth" in options || "gender" in options) {
|
|
575
589
|
email = options.email;
|
|
576
590
|
properties = options.properties;
|
|
577
591
|
} else {
|
|
@@ -591,9 +605,36 @@ var init_IdentityManager = __esm({
|
|
|
591
605
|
this.properties = { ...this.properties, ...properties };
|
|
592
606
|
await this.secureStorage.set(USER_PROPERTIES_KEY, JSON.stringify(this.properties));
|
|
593
607
|
}
|
|
608
|
+
const opts = options;
|
|
609
|
+
if (opts?.phone) {
|
|
610
|
+
this.phone = opts.phone;
|
|
611
|
+
await this.secureStorage.set(USER_PHONE_KEY, this.phone);
|
|
612
|
+
}
|
|
613
|
+
if (opts?.firstName) {
|
|
614
|
+
this.firstName = opts.firstName;
|
|
615
|
+
await this.secureStorage.set(USER_FIRST_NAME_KEY, this.firstName);
|
|
616
|
+
}
|
|
617
|
+
if (opts?.lastName) {
|
|
618
|
+
this.lastName = opts.lastName;
|
|
619
|
+
await this.secureStorage.set(USER_LAST_NAME_KEY, this.lastName);
|
|
620
|
+
}
|
|
621
|
+
if (opts?.dateOfBirth) {
|
|
622
|
+
this.dateOfBirth = opts.dateOfBirth;
|
|
623
|
+
await this.secureStorage.set(USER_DOB_KEY, this.dateOfBirth);
|
|
624
|
+
}
|
|
625
|
+
if (opts?.gender) {
|
|
626
|
+
this.gender = opts.gender;
|
|
627
|
+
await this.secureStorage.set(USER_GENDER_KEY, this.gender);
|
|
628
|
+
}
|
|
594
629
|
if (this.apiClient && this.anonId) {
|
|
595
630
|
try {
|
|
596
|
-
await this.apiClient.identify(this.anonId, properties, email, this.deviceId ?? void 0
|
|
631
|
+
await this.apiClient.identify(this.anonId, properties, email, this.deviceId ?? void 0, {
|
|
632
|
+
phone: this.phone ?? void 0,
|
|
633
|
+
firstName: this.firstName ?? void 0,
|
|
634
|
+
lastName: this.lastName ?? void 0,
|
|
635
|
+
dateOfBirth: this.dateOfBirth ?? void 0,
|
|
636
|
+
gender: this.gender ?? void 0
|
|
637
|
+
});
|
|
597
638
|
} catch {
|
|
598
639
|
}
|
|
599
640
|
}
|
|
@@ -628,17 +669,32 @@ var init_IdentityManager = __esm({
|
|
|
628
669
|
this.distinctId = null;
|
|
629
670
|
this.email = null;
|
|
630
671
|
this.properties = {};
|
|
672
|
+
this.phone = null;
|
|
673
|
+
this.firstName = null;
|
|
674
|
+
this.lastName = null;
|
|
675
|
+
this.dateOfBirth = null;
|
|
676
|
+
this.gender = null;
|
|
631
677
|
await Promise.all([
|
|
632
678
|
this.secureStorage?.set(ANON_ID_KEY, newAnonId) ?? Promise.resolve(false),
|
|
633
679
|
this.secureStorage?.remove(USER_EMAIL_KEY) ?? Promise.resolve(false),
|
|
634
|
-
this.secureStorage?.remove(USER_PROPERTIES_KEY) ?? Promise.resolve(false)
|
|
680
|
+
this.secureStorage?.remove(USER_PROPERTIES_KEY) ?? Promise.resolve(false),
|
|
681
|
+
this.secureStorage?.remove(USER_PHONE_KEY) ?? Promise.resolve(false),
|
|
682
|
+
this.secureStorage?.remove(USER_FIRST_NAME_KEY) ?? Promise.resolve(false),
|
|
683
|
+
this.secureStorage?.remove(USER_LAST_NAME_KEY) ?? Promise.resolve(false),
|
|
684
|
+
this.secureStorage?.remove(USER_DOB_KEY) ?? Promise.resolve(false),
|
|
685
|
+
this.secureStorage?.remove(USER_GENDER_KEY) ?? Promise.resolve(false)
|
|
635
686
|
]);
|
|
636
687
|
}
|
|
637
688
|
getState() {
|
|
638
689
|
return {
|
|
639
690
|
deviceId: this.deviceId ?? "",
|
|
640
691
|
email: this.email,
|
|
641
|
-
properties: this.getProperties()
|
|
692
|
+
properties: this.getProperties(),
|
|
693
|
+
phone: this.phone,
|
|
694
|
+
firstName: this.firstName,
|
|
695
|
+
lastName: this.lastName,
|
|
696
|
+
dateOfBirth: this.dateOfBirth,
|
|
697
|
+
gender: this.gender
|
|
642
698
|
};
|
|
643
699
|
}
|
|
644
700
|
isSecureStorageAvailable() {
|
|
@@ -663,6 +719,18 @@ var init_IdentityManager = __esm({
|
|
|
663
719
|
if (state.email) this.email = state.email;
|
|
664
720
|
if (state.propertiesJson) this.properties = parseProperties(state.propertiesJson);
|
|
665
721
|
if (state.distinctId) this.distinctId = state.distinctId;
|
|
722
|
+
const [phone, firstName, lastName, dateOfBirth, gender] = await Promise.all([
|
|
723
|
+
this.secureStorage.get(USER_PHONE_KEY),
|
|
724
|
+
this.secureStorage.get(USER_FIRST_NAME_KEY),
|
|
725
|
+
this.secureStorage.get(USER_LAST_NAME_KEY),
|
|
726
|
+
this.secureStorage.get(USER_DOB_KEY),
|
|
727
|
+
this.secureStorage.get(USER_GENDER_KEY)
|
|
728
|
+
]);
|
|
729
|
+
if (phone) this.phone = phone;
|
|
730
|
+
if (firstName) this.firstName = firstName;
|
|
731
|
+
if (lastName) this.lastName = lastName;
|
|
732
|
+
if (dateOfBirth) this.dateOfBirth = dateOfBirth;
|
|
733
|
+
if (gender) this.gender = gender;
|
|
666
734
|
}
|
|
667
735
|
ensureInitialized() {
|
|
668
736
|
if (!this.initialized) {
|
|
@@ -803,7 +871,8 @@ var init_NativeStoreKit = __esm({
|
|
|
803
871
|
);
|
|
804
872
|
}
|
|
805
873
|
const distinctId = identityManager.getDistinctId();
|
|
806
|
-
const
|
|
874
|
+
const rawUuid = distinctId?.startsWith("$paywallo_anon:") ? distinctId.slice("$paywallo_anon:".length) : distinctId;
|
|
875
|
+
const appAccountToken = isValidUUIDv4(rawUuid) ? rawUuid : null;
|
|
807
876
|
if (distinctId && appAccountToken === null) {
|
|
808
877
|
if (PaywalloClient.getConfig()?.debug) console.log("[Paywallo] distinctId is not a valid UUID v4 \u2014 passing null to appAccountToken:", distinctId);
|
|
809
878
|
}
|
|
@@ -2283,6 +2352,7 @@ var init_usePaywallTracking = __esm({
|
|
|
2283
2352
|
// src/domains/paywall/usePaywallActions.ts
|
|
2284
2353
|
function usePaywallActions(placement, paywallConfig, onResult, variantKey, campaignId, openAnim, variantId) {
|
|
2285
2354
|
const [isPurchasing, setIsPurchasing] = (0, import_react2.useState)(false);
|
|
2355
|
+
const isPurchasingRef = (0, import_react2.useRef)(false);
|
|
2286
2356
|
const [isClosing, setIsClosing] = (0, import_react2.useState)(false);
|
|
2287
2357
|
const slideAnim = (0, import_react2.useRef)(new import_react_native7.Animated.Value(0)).current;
|
|
2288
2358
|
const presentedAtRef = (0, import_react2.useRef)(Date.now());
|
|
@@ -2314,6 +2384,7 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
2314
2384
|
}, [isClosing, closeWithReason]);
|
|
2315
2385
|
(0, import_react2.useEffect)(() => {
|
|
2316
2386
|
const sub = import_react_native7.AppState.addEventListener("change", (nextState) => {
|
|
2387
|
+
if (isPurchasingRef.current) return;
|
|
2317
2388
|
if (nextState === "background" || nextState === "inactive") {
|
|
2318
2389
|
closeWithReason("backgrounded");
|
|
2319
2390
|
}
|
|
@@ -2329,6 +2400,7 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
2329
2400
|
const handlePurchase = (0, import_react2.useCallback)(async (productId) => {
|
|
2330
2401
|
if (isPurchasing) return;
|
|
2331
2402
|
setIsPurchasing(true);
|
|
2403
|
+
isPurchasingRef.current = true;
|
|
2332
2404
|
try {
|
|
2333
2405
|
if (paywallConfig) trackProductSelected({ placement, paywallId: paywallConfig.id, productId, variantKey, campaignId, variantId });
|
|
2334
2406
|
const result = await getIAPService().purchase(productId, {
|
|
@@ -2351,12 +2423,14 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
2351
2423
|
} catch (error) {
|
|
2352
2424
|
onResult({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
2353
2425
|
} finally {
|
|
2426
|
+
isPurchasingRef.current = false;
|
|
2354
2427
|
setIsPurchasing(false);
|
|
2355
2428
|
}
|
|
2356
2429
|
}, [isPurchasing, onResult, paywallConfig, placement, trackDismissed, trackProductSelected, trackPurchased, variantKey, campaignId, variantId]);
|
|
2357
2430
|
const handleRestore = (0, import_react2.useCallback)(async () => {
|
|
2358
2431
|
if (isPurchasing) return;
|
|
2359
2432
|
setIsPurchasing(true);
|
|
2433
|
+
isPurchasingRef.current = true;
|
|
2360
2434
|
try {
|
|
2361
2435
|
const transactions = await getIAPService().restore();
|
|
2362
2436
|
if (transactions.length > 0) {
|
|
@@ -2371,6 +2445,7 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
2371
2445
|
} catch (error) {
|
|
2372
2446
|
onResult({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
2373
2447
|
} finally {
|
|
2448
|
+
isPurchasingRef.current = false;
|
|
2374
2449
|
setIsPurchasing(false);
|
|
2375
2450
|
}
|
|
2376
2451
|
}, [isPurchasing, onResult, paywallConfig, placement, trackDismissed, variantKey, campaignId, variantId]);
|
|
@@ -2473,7 +2548,8 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
2473
2548
|
if (!trackingDoneRef.current && !cancelled) {
|
|
2474
2549
|
trackingDoneRef.current = true;
|
|
2475
2550
|
const sessionId = PaywalloClient.getSessionId();
|
|
2476
|
-
|
|
2551
|
+
const distinctId = PaywalloClient.getDistinctId();
|
|
2552
|
+
await apiClient.trackEvent("$paywall_viewed", distinctId, {
|
|
2477
2553
|
placement,
|
|
2478
2554
|
paywallId: config.id,
|
|
2479
2555
|
...sessionId && { sessionId },
|
|
@@ -2481,6 +2557,16 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
2481
2557
|
...campaignId && { campaignId },
|
|
2482
2558
|
...variantId && { variant_id: variantId }
|
|
2483
2559
|
});
|
|
2560
|
+
await apiClient.trackEvent("paywall", distinctId, {
|
|
2561
|
+
type: "open",
|
|
2562
|
+
paywall_id: config.id,
|
|
2563
|
+
placement,
|
|
2564
|
+
opened_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2565
|
+
...sessionId && { sessionId },
|
|
2566
|
+
...variantKey && { variant_key: variantKey },
|
|
2567
|
+
...campaignId && { campaign_id: campaignId },
|
|
2568
|
+
...variantId && { variant_id: variantId }
|
|
2569
|
+
});
|
|
2484
2570
|
}
|
|
2485
2571
|
} catch (err) {
|
|
2486
2572
|
if (cancelled) return;
|
|
@@ -2657,15 +2743,21 @@ var init_paywallScripts = __esm({
|
|
|
2657
2743
|
|
|
2658
2744
|
// src/domains/paywall/PaywallWebView.tsx
|
|
2659
2745
|
function getNativeWebView() {
|
|
2660
|
-
if (
|
|
2746
|
+
if (NativeWebViewComponent) return NativeWebViewComponent;
|
|
2747
|
+
if (nativeWebViewLookupFailed) return null;
|
|
2748
|
+
try {
|
|
2661
2749
|
NativeWebViewComponent = (0, import_react_native9.requireNativeComponent)("PaywalloWebView");
|
|
2750
|
+
return NativeWebViewComponent;
|
|
2751
|
+
} catch {
|
|
2752
|
+
nativeWebViewLookupFailed = true;
|
|
2753
|
+
return null;
|
|
2662
2754
|
}
|
|
2663
|
-
return NativeWebViewComponent;
|
|
2664
2755
|
}
|
|
2665
2756
|
function getWebViewEmitter() {
|
|
2666
|
-
if (
|
|
2667
|
-
|
|
2668
|
-
|
|
2757
|
+
if (webViewEmitter) return webViewEmitter;
|
|
2758
|
+
const mod = import_react_native9.NativeModules.PaywalloWebViewModule;
|
|
2759
|
+
if (!mod) return null;
|
|
2760
|
+
webViewEmitter = new import_react_native9.NativeEventEmitter(mod);
|
|
2669
2761
|
return webViewEmitter;
|
|
2670
2762
|
}
|
|
2671
2763
|
function parseErrorEvent(raw) {
|
|
@@ -2697,6 +2789,14 @@ function PaywallWebView({
|
|
|
2697
2789
|
const onReadyRef = (0, import_react4.useRef)(onReady);
|
|
2698
2790
|
onReadyRef.current = onReady;
|
|
2699
2791
|
const NativeWebView = (0, import_react4.useMemo)(() => getNativeWebView(), []);
|
|
2792
|
+
(0, import_react4.useEffect)(() => {
|
|
2793
|
+
if (!NativeWebView) {
|
|
2794
|
+
onErrorRef.current?.({
|
|
2795
|
+
code: -1,
|
|
2796
|
+
description: "Paywallo native module not linked. Run `pod install` (iOS) or rebuild the Android app."
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
}, [NativeWebView]);
|
|
2700
2800
|
const [resolvedWebUrl, setResolvedWebUrl] = (0, import_react4.useState)(
|
|
2701
2801
|
() => webUrlProp ?? PaywalloClient.getWebUrl()
|
|
2702
2802
|
);
|
|
@@ -2788,6 +2888,7 @@ function PaywallWebView({
|
|
|
2788
2888
|
);
|
|
2789
2889
|
(0, import_react4.useEffect)(() => {
|
|
2790
2890
|
const emitter = getWebViewEmitter();
|
|
2891
|
+
if (!emitter) return;
|
|
2791
2892
|
const loadEndSub = emitter.addListener("PaywalloWebViewLoadEnd", () => {
|
|
2792
2893
|
if (!loadEndReceived.current) {
|
|
2793
2894
|
loadEndReceived.current = true;
|
|
@@ -2854,7 +2955,7 @@ function PaywallWebView({
|
|
|
2854
2955
|
if (!paywallDataSent.current) return;
|
|
2855
2956
|
setScriptToInject(buildPurchaseStateScript(isPurchasing));
|
|
2856
2957
|
}, [isPurchasing]);
|
|
2857
|
-
if (!resolvedWebUrl) return null;
|
|
2958
|
+
if (!resolvedWebUrl || !NativeWebView) return null;
|
|
2858
2959
|
const paywallUrl = `${resolvedWebUrl}/paywall/${paywallId}`;
|
|
2859
2960
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native9.View, { style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2860
2961
|
NativeWebView,
|
|
@@ -2868,7 +2969,7 @@ function PaywallWebView({
|
|
|
2868
2969
|
}
|
|
2869
2970
|
) });
|
|
2870
2971
|
}
|
|
2871
|
-
var import_react4, import_react_native9, import_jsx_runtime, NativeWebViewComponent, webViewEmitter, styles;
|
|
2972
|
+
var import_react4, import_react_native9, import_jsx_runtime, NativeWebViewComponent, nativeWebViewLookupFailed, webViewEmitter, styles;
|
|
2872
2973
|
var init_PaywallWebView = __esm({
|
|
2873
2974
|
"src/domains/paywall/PaywallWebView.tsx"() {
|
|
2874
2975
|
"use strict";
|
|
@@ -2879,6 +2980,7 @@ var init_PaywallWebView = __esm({
|
|
|
2879
2980
|
init_paywallScripts();
|
|
2880
2981
|
import_jsx_runtime = require("react/jsx-runtime");
|
|
2881
2982
|
NativeWebViewComponent = null;
|
|
2983
|
+
nativeWebViewLookupFailed = false;
|
|
2882
2984
|
webViewEmitter = null;
|
|
2883
2985
|
styles = import_react_native9.StyleSheet.create({
|
|
2884
2986
|
container: { flex: 1 },
|
|
@@ -3196,7 +3298,8 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
3196
3298
|
const apiClient = PaywalloClient.getApiClient();
|
|
3197
3299
|
if (apiClient && preloadedWebView) {
|
|
3198
3300
|
const sessionId = PaywalloClient.getSessionId();
|
|
3199
|
-
|
|
3301
|
+
const distinctId = PaywalloClient.getDistinctId();
|
|
3302
|
+
void apiClient.trackEvent("$paywall_viewed", distinctId, {
|
|
3200
3303
|
placement: preloadedWebView.placement,
|
|
3201
3304
|
paywallId: preloadedWebView.paywallId,
|
|
3202
3305
|
preloaded: true,
|
|
@@ -3206,6 +3309,18 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
3206
3309
|
...sessionId && { sessionId }
|
|
3207
3310
|
}).catch(() => {
|
|
3208
3311
|
});
|
|
3312
|
+
void apiClient.trackEvent("paywall", distinctId, {
|
|
3313
|
+
type: "open",
|
|
3314
|
+
paywall_id: preloadedWebView.paywallId,
|
|
3315
|
+
placement: preloadedWebView.placement,
|
|
3316
|
+
opened_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3317
|
+
preloaded: true,
|
|
3318
|
+
...preloadedWebView.variantKey && { variant_key: preloadedWebView.variantKey },
|
|
3319
|
+
...preloadedWebView.campaignId && { campaign_id: preloadedWebView.campaignId },
|
|
3320
|
+
...preloadedWebView.variantId && { variant_id: preloadedWebView.variantId },
|
|
3321
|
+
...sessionId && { sessionId }
|
|
3322
|
+
}).catch(() => {
|
|
3323
|
+
});
|
|
3209
3324
|
}
|
|
3210
3325
|
});
|
|
3211
3326
|
}, [preloadedWebView]);
|
|
@@ -3300,6 +3415,8 @@ var init_CampaignGateService = __esm({
|
|
|
3300
3415
|
constructor() {
|
|
3301
3416
|
this.preloadedCampaigns = /* @__PURE__ */ new Map();
|
|
3302
3417
|
this.pendingPreloads = /* @__PURE__ */ new Set();
|
|
3418
|
+
this.apiClientRef = null;
|
|
3419
|
+
this.STALE_THRESHOLD = 0.8;
|
|
3303
3420
|
this.activePreloadPromises = /* @__PURE__ */ new Map();
|
|
3304
3421
|
}
|
|
3305
3422
|
async getCampaign(apiClient, placement, context) {
|
|
@@ -3382,12 +3499,29 @@ var init_CampaignGateService = __esm({
|
|
|
3382
3499
|
getPreloadedCampaign(placement) {
|
|
3383
3500
|
const cached = this.preloadedCampaigns.get(placement);
|
|
3384
3501
|
if (!cached) return null;
|
|
3385
|
-
|
|
3502
|
+
const age = Date.now() - cached.preloadedAt;
|
|
3503
|
+
if (age >= PRELOAD_CACHE_TTL_MS) {
|
|
3386
3504
|
this.preloadedCampaigns.delete(placement);
|
|
3387
3505
|
return null;
|
|
3388
3506
|
}
|
|
3507
|
+
if (age >= PRELOAD_CACHE_TTL_MS * this.STALE_THRESHOLD && this.apiClientRef) {
|
|
3508
|
+
void this.preloadCampaign(this.apiClientRef, placement).catch(() => {
|
|
3509
|
+
});
|
|
3510
|
+
}
|
|
3389
3511
|
return cached.campaign;
|
|
3390
3512
|
}
|
|
3513
|
+
async preloadAllActive(apiClient, debug) {
|
|
3514
|
+
this.apiClientRef = apiClient;
|
|
3515
|
+
const placements = await apiClient.getActivePlacements();
|
|
3516
|
+
if (placements.length === 0) return;
|
|
3517
|
+
if (debug) console.log(`[Paywallo PRELOAD] auto-preloading ${placements.length} placements`);
|
|
3518
|
+
for (let i = 0; i < placements.length; i++) {
|
|
3519
|
+
if (i > 0) await new Promise((r) => setTimeout(r, 500));
|
|
3520
|
+
void this.preloadCampaign(apiClient, placements[i]).catch((err) => {
|
|
3521
|
+
if (debug) console.log(`[Paywallo PRELOAD] failed ${placements[i]}:`, err);
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3391
3525
|
clearPreloaded() {
|
|
3392
3526
|
this.preloadedCampaigns.clear();
|
|
3393
3527
|
this.pendingPreloads.clear();
|
|
@@ -3407,7 +3541,7 @@ var init_campaign = __esm({
|
|
|
3407
3541
|
});
|
|
3408
3542
|
|
|
3409
3543
|
// src/domains/identity/AdvertisingIdManager.ts
|
|
3410
|
-
var import_react_native11, ZERO_IDFA, AdvertisingIdManager;
|
|
3544
|
+
var import_react_native11, ZERO_IDFA, AdvertisingIdManager, advertisingIdManager;
|
|
3411
3545
|
var init_AdvertisingIdManager = __esm({
|
|
3412
3546
|
"src/domains/identity/AdvertisingIdManager.ts"() {
|
|
3413
3547
|
"use strict";
|
|
@@ -3418,6 +3552,14 @@ var init_AdvertisingIdManager = __esm({
|
|
|
3418
3552
|
constructor() {
|
|
3419
3553
|
this.cached = null;
|
|
3420
3554
|
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Synchronous accessor for the cached collect() result. Returns null until
|
|
3557
|
+
* `collect()` resolves at least once. Used by the V2 envelope context
|
|
3558
|
+
* provider — which is sync — to populate `context.ids` without awaiting.
|
|
3559
|
+
*/
|
|
3560
|
+
getCached() {
|
|
3561
|
+
return this.cached;
|
|
3562
|
+
}
|
|
3421
3563
|
async collect(requestATT = false) {
|
|
3422
3564
|
if (this.cached) return this.cached;
|
|
3423
3565
|
const fallback = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
|
|
@@ -3468,136 +3610,26 @@ var init_AdvertisingIdManager = __esm({
|
|
|
3468
3610
|
return id;
|
|
3469
3611
|
}
|
|
3470
3612
|
};
|
|
3613
|
+
advertisingIdManager = new AdvertisingIdManager();
|
|
3471
3614
|
}
|
|
3472
3615
|
});
|
|
3473
3616
|
|
|
3474
|
-
// src/domains/
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
NativeBridge = import_react_native12.NativeModules.PaywalloFBBridge ?? null;
|
|
3482
|
-
MetaBridge = class {
|
|
3483
|
-
async getAnonymousID() {
|
|
3484
|
-
if (!NativeBridge) return null;
|
|
3485
|
-
try {
|
|
3486
|
-
let timerId;
|
|
3487
|
-
const timeout = new Promise((resolve) => {
|
|
3488
|
-
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
3489
|
-
});
|
|
3490
|
-
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
3491
|
-
clearTimeout(timerId);
|
|
3492
|
-
return result;
|
|
3493
|
-
} catch {
|
|
3494
|
-
return null;
|
|
3495
|
-
}
|
|
3496
|
-
}
|
|
3497
|
-
async logEvent(name, params = {}) {
|
|
3498
|
-
if (!NativeBridge) return;
|
|
3499
|
-
try {
|
|
3500
|
-
await NativeBridge.logEvent(name, params);
|
|
3501
|
-
} catch (error) {
|
|
3502
|
-
console.warn("[Paywallo:MetaBridge] logEvent failed", { name, error });
|
|
3503
|
-
}
|
|
3504
|
-
}
|
|
3505
|
-
async logPurchase(amount, currency, params = {}) {
|
|
3506
|
-
if (!NativeBridge) return;
|
|
3507
|
-
try {
|
|
3508
|
-
await NativeBridge.logPurchase(amount, currency, params);
|
|
3509
|
-
} catch (error) {
|
|
3510
|
-
console.warn("[Paywallo:MetaBridge] logPurchase failed", { amount, currency, error });
|
|
3511
|
-
}
|
|
3512
|
-
}
|
|
3513
|
-
setUserID(userId) {
|
|
3514
|
-
if (!NativeBridge) return;
|
|
3515
|
-
try {
|
|
3516
|
-
NativeBridge.setUserID(userId);
|
|
3517
|
-
} catch (error) {
|
|
3518
|
-
console.warn("[Paywallo:MetaBridge] setUserID failed", { error });
|
|
3519
|
-
}
|
|
3520
|
-
}
|
|
3521
|
-
flush() {
|
|
3522
|
-
if (!NativeBridge) return;
|
|
3523
|
-
try {
|
|
3524
|
-
NativeBridge.flush();
|
|
3525
|
-
} catch (error) {
|
|
3526
|
-
console.warn("[Paywallo:MetaBridge] flush failed", { error });
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
};
|
|
3530
|
-
metaBridge = new MetaBridge();
|
|
3617
|
+
// src/domains/session/distinctIdGuard.ts
|
|
3618
|
+
async function waitForDistinctId(provider, retries = DISTINCT_ID_WAIT_RETRIES, intervalMs = DISTINCT_ID_WAIT_INTERVAL_MS) {
|
|
3619
|
+
if (!provider) return true;
|
|
3620
|
+
if (provider()) return true;
|
|
3621
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
3622
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3623
|
+
if (provider()) return true;
|
|
3531
3624
|
}
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
var
|
|
3536
|
-
|
|
3537
|
-
"src/domains/identity/InstallReferrerManager.ts"() {
|
|
3625
|
+
return false;
|
|
3626
|
+
}
|
|
3627
|
+
var DISTINCT_ID_WAIT_RETRIES, DISTINCT_ID_WAIT_INTERVAL_MS;
|
|
3628
|
+
var init_distinctIdGuard = __esm({
|
|
3629
|
+
"src/domains/session/distinctIdGuard.ts"() {
|
|
3538
3630
|
"use strict";
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
REFERRER_TIMEOUT_MS = 5e3;
|
|
3542
|
-
InstallReferrerManager = class {
|
|
3543
|
-
async getReferrer() {
|
|
3544
|
-
if (import_react_native13.Platform.OS !== "android") {
|
|
3545
|
-
return this.emptyResult();
|
|
3546
|
-
}
|
|
3547
|
-
let timerId;
|
|
3548
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
3549
|
-
timerId = setTimeout(() => resolve(this.emptyResult()), REFERRER_TIMEOUT_MS);
|
|
3550
|
-
});
|
|
3551
|
-
const fetchPromise = this.fetchReferrer();
|
|
3552
|
-
const result = await Promise.race([fetchPromise, timeoutPromise]);
|
|
3553
|
-
clearTimeout(timerId);
|
|
3554
|
-
return result;
|
|
3555
|
-
}
|
|
3556
|
-
async fetchReferrer() {
|
|
3557
|
-
try {
|
|
3558
|
-
const referrer = await nativeDeviceInfo.getInstallReferrer();
|
|
3559
|
-
if (!referrer) return this.emptyResult();
|
|
3560
|
-
const capped = referrer.slice(0, 2048);
|
|
3561
|
-
const params = this.parseReferrer(capped);
|
|
3562
|
-
return {
|
|
3563
|
-
rawReferrer: capped,
|
|
3564
|
-
trackingId: params["tracking_id"] || null,
|
|
3565
|
-
fbclid: params["fbclid"] || null,
|
|
3566
|
-
utmSource: params["utm_source"] || null,
|
|
3567
|
-
utmMedium: params["utm_medium"] || null,
|
|
3568
|
-
utmCampaign: params["utm_campaign"] || null
|
|
3569
|
-
};
|
|
3570
|
-
} catch {
|
|
3571
|
-
return this.emptyResult();
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
parseReferrer(referrer) {
|
|
3575
|
-
const result = {};
|
|
3576
|
-
for (const pair of referrer.split("&")) {
|
|
3577
|
-
const eqIndex = pair.indexOf("=");
|
|
3578
|
-
if (eqIndex === -1) continue;
|
|
3579
|
-
try {
|
|
3580
|
-
const key = decodeURIComponent(pair.slice(0, eqIndex).replace(/\+/g, " "));
|
|
3581
|
-
const raw = pair.slice(eqIndex + 1).replace(/\+/g, " ");
|
|
3582
|
-
const value = decodeURIComponent(raw);
|
|
3583
|
-
if (key) result[key] = value;
|
|
3584
|
-
} catch {
|
|
3585
|
-
}
|
|
3586
|
-
}
|
|
3587
|
-
return result;
|
|
3588
|
-
}
|
|
3589
|
-
emptyResult() {
|
|
3590
|
-
return {
|
|
3591
|
-
rawReferrer: null,
|
|
3592
|
-
trackingId: null,
|
|
3593
|
-
fbclid: null,
|
|
3594
|
-
utmSource: null,
|
|
3595
|
-
utmMedium: null,
|
|
3596
|
-
utmCampaign: null
|
|
3597
|
-
};
|
|
3598
|
-
}
|
|
3599
|
-
};
|
|
3600
|
-
installReferrerManager = new InstallReferrerManager();
|
|
3631
|
+
DISTINCT_ID_WAIT_RETRIES = 10;
|
|
3632
|
+
DISTINCT_ID_WAIT_INTERVAL_MS = 100;
|
|
3601
3633
|
}
|
|
3602
3634
|
});
|
|
3603
3635
|
|
|
@@ -3622,25 +3654,6 @@ var init_SessionError = __esm({
|
|
|
3622
3654
|
}
|
|
3623
3655
|
});
|
|
3624
3656
|
|
|
3625
|
-
// src/domains/session/distinctIdGuard.ts
|
|
3626
|
-
async function waitForDistinctId(provider, retries = DISTINCT_ID_WAIT_RETRIES, intervalMs = DISTINCT_ID_WAIT_INTERVAL_MS) {
|
|
3627
|
-
if (!provider) return true;
|
|
3628
|
-
if (provider()) return true;
|
|
3629
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
3630
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
3631
|
-
if (provider()) return true;
|
|
3632
|
-
}
|
|
3633
|
-
return false;
|
|
3634
|
-
}
|
|
3635
|
-
var DISTINCT_ID_WAIT_RETRIES, DISTINCT_ID_WAIT_INTERVAL_MS;
|
|
3636
|
-
var init_distinctIdGuard = __esm({
|
|
3637
|
-
"src/domains/session/distinctIdGuard.ts"() {
|
|
3638
|
-
"use strict";
|
|
3639
|
-
DISTINCT_ID_WAIT_RETRIES = 10;
|
|
3640
|
-
DISTINCT_ID_WAIT_INTERVAL_MS = 100;
|
|
3641
|
-
}
|
|
3642
|
-
});
|
|
3643
|
-
|
|
3644
3657
|
// src/utils/deviceInfo.ts
|
|
3645
3658
|
var deviceInfo_exports = {};
|
|
3646
3659
|
__export(deviceInfo_exports, {
|
|
@@ -3651,7 +3664,9 @@ async function collectDeviceInfo() {
|
|
|
3651
3664
|
return {
|
|
3652
3665
|
appVersion: result.appVersion,
|
|
3653
3666
|
deviceModel: result.model,
|
|
3654
|
-
osVersion: result.systemVersion
|
|
3667
|
+
osVersion: result.systemVersion,
|
|
3668
|
+
darwinVersion: result.darwinVersion,
|
|
3669
|
+
webkitVersion: result.webkitVersion
|
|
3655
3670
|
};
|
|
3656
3671
|
}
|
|
3657
3672
|
var init_deviceInfo = __esm({
|
|
@@ -3719,11 +3734,11 @@ var init_sessionTracking = __esm({
|
|
|
3719
3734
|
});
|
|
3720
3735
|
|
|
3721
3736
|
// src/domains/session/SessionManager.ts
|
|
3722
|
-
var
|
|
3737
|
+
var import_react_native12, SESSION_ID_KEY, SESSION_START_KEY, EMERGENCY_PAYWALL_SHOWN_KEY, LEGACY_SESSION_ID_KEY, LEGACY_SESSION_START_KEY, SESSION_TIMEOUT_MS, BACKGROUND_FLUSH_TIMEOUT_MS, SessionManager, sessionManager;
|
|
3723
3738
|
var init_SessionManager = __esm({
|
|
3724
3739
|
"src/domains/session/SessionManager.ts"() {
|
|
3725
3740
|
"use strict";
|
|
3726
|
-
|
|
3741
|
+
import_react_native12 = require("react-native");
|
|
3727
3742
|
init_SessionError();
|
|
3728
3743
|
init_uuid();
|
|
3729
3744
|
init_distinctIdGuard();
|
|
@@ -3882,7 +3897,7 @@ var init_SessionManager = __esm({
|
|
|
3882
3897
|
if (this.appStateSubscription) {
|
|
3883
3898
|
this.appStateSubscription.remove();
|
|
3884
3899
|
}
|
|
3885
|
-
this.appStateSubscription =
|
|
3900
|
+
this.appStateSubscription = import_react_native12.AppState.addEventListener("change", this.handleAppStateChange);
|
|
3886
3901
|
}
|
|
3887
3902
|
async handleForeground() {
|
|
3888
3903
|
const elapsed = this.backgroundTimestamp ? Date.now() - this.backgroundTimestamp : null;
|
|
@@ -3951,57 +3966,6 @@ var init_SessionManager = __esm({
|
|
|
3951
3966
|
}
|
|
3952
3967
|
});
|
|
3953
3968
|
|
|
3954
|
-
// src/domains/identity/InstallIdempotency.ts
|
|
3955
|
-
async function checkAndArmInstallGuard(storage) {
|
|
3956
|
-
const alreadyTracked = await storage.get(INSTALL_KEYS.INSTALL_TRACKED);
|
|
3957
|
-
if (alreadyTracked) return true;
|
|
3958
|
-
let fallbackTracked = null;
|
|
3959
|
-
try {
|
|
3960
|
-
fallbackTracked = await nativeStorage.get(INSTALL_KEYS.LEGACY_INSTALL_TRACKED);
|
|
3961
|
-
} catch {
|
|
3962
|
-
}
|
|
3963
|
-
if (fallbackTracked) return true;
|
|
3964
|
-
await nativeStorage.set(INSTALL_KEYS.INSTALL_SENT, "1");
|
|
3965
|
-
return false;
|
|
3966
|
-
}
|
|
3967
|
-
async function markInstallTracked(storage, installedAt) {
|
|
3968
|
-
await storage.set(INSTALL_KEYS.INSTALL_TRACKED, String(installedAt));
|
|
3969
|
-
try {
|
|
3970
|
-
await nativeStorage.set(INSTALL_KEYS.LEGACY_INSTALL_TRACKED, String(installedAt));
|
|
3971
|
-
} catch {
|
|
3972
|
-
}
|
|
3973
|
-
}
|
|
3974
|
-
async function getOrCreateInstallEventId() {
|
|
3975
|
-
const existing = await nativeStorage.get(INSTALL_KEYS.INSTALL_EVENT_ID);
|
|
3976
|
-
if (existing) return existing;
|
|
3977
|
-
const { generateUUID: generateUUID2 } = await Promise.resolve().then(() => (init_uuid(), uuid_exports));
|
|
3978
|
-
const id = generateUUID2();
|
|
3979
|
-
await nativeStorage.set(INSTALL_KEYS.INSTALL_EVENT_ID, id).catch(() => {
|
|
3980
|
-
});
|
|
3981
|
-
return id;
|
|
3982
|
-
}
|
|
3983
|
-
var INSTALL_KEYS;
|
|
3984
|
-
var init_InstallIdempotency = __esm({
|
|
3985
|
-
"src/domains/identity/InstallIdempotency.ts"() {
|
|
3986
|
-
"use strict";
|
|
3987
|
-
init_NativeStorage();
|
|
3988
|
-
INSTALL_KEYS = {
|
|
3989
|
-
/** Primary flag — set AFTER a successful $app_installed dispatch. */
|
|
3990
|
-
INSTALL_TRACKED: "@panel:install_tracked",
|
|
3991
|
-
/** Legacy fallback flag written by older SDK versions. */
|
|
3992
|
-
LEGACY_INSTALL_TRACKED: "@paywallo:install_tracked",
|
|
3993
|
-
/** Pre-send guard — set BEFORE dispatching to survive concurrent cold-starts. */
|
|
3994
|
-
INSTALL_SENT: "@paywallo:app_installed_sent",
|
|
3995
|
-
/** Stable event ID for backend dedup — generated once, reused on retries. */
|
|
3996
|
-
INSTALL_EVENT_ID: "@panel:install_event_id",
|
|
3997
|
-
/** Deferred match flag — set once iOS fingerprint match succeeds. */
|
|
3998
|
-
DEFERRED_MATCH_DONE: "@panel:deferred_match_done",
|
|
3999
|
-
/** Anonymous ID fallback when FB SDK not available. */
|
|
4000
|
-
ANON_ID: "@panel:anon_id"
|
|
4001
|
-
};
|
|
4002
|
-
}
|
|
4003
|
-
});
|
|
4004
|
-
|
|
4005
3969
|
// src/domains/identity/AttributionTracker.ts
|
|
4006
3970
|
function hasAnyField(data) {
|
|
4007
3971
|
return Object.values(data).some((v) => v !== void 0 && v !== null && v !== "");
|
|
@@ -4073,21 +4037,212 @@ var init_AttributionTracker = __esm({
|
|
|
4073
4037
|
}
|
|
4074
4038
|
});
|
|
4075
4039
|
|
|
4076
|
-
// src/domains/identity/
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4040
|
+
// src/domains/identity/InstallIdempotency.ts
|
|
4041
|
+
async function checkAndArmInstallGuard(storage) {
|
|
4042
|
+
const alreadyTracked = await storage.get(INSTALL_KEYS.INSTALL_TRACKED);
|
|
4043
|
+
if (alreadyTracked) return true;
|
|
4044
|
+
let fallbackTracked = null;
|
|
4045
|
+
try {
|
|
4046
|
+
fallbackTracked = await nativeStorage.get(INSTALL_KEYS.LEGACY_INSTALL_TRACKED);
|
|
4047
|
+
} catch {
|
|
4048
|
+
}
|
|
4049
|
+
if (fallbackTracked) return true;
|
|
4050
|
+
await nativeStorage.set(INSTALL_KEYS.INSTALL_SENT, "1");
|
|
4051
|
+
return false;
|
|
4052
|
+
}
|
|
4053
|
+
async function markInstallTracked(storage, installedAt) {
|
|
4054
|
+
await storage.set(INSTALL_KEYS.INSTALL_TRACKED, String(installedAt));
|
|
4055
|
+
try {
|
|
4056
|
+
await nativeStorage.set(INSTALL_KEYS.LEGACY_INSTALL_TRACKED, String(installedAt));
|
|
4057
|
+
} catch {
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
async function getOrCreateInstallEventId() {
|
|
4061
|
+
const existing = await nativeStorage.get(INSTALL_KEYS.INSTALL_EVENT_ID);
|
|
4062
|
+
if (existing) return existing;
|
|
4063
|
+
const { generateUUID: generateUUID2 } = await Promise.resolve().then(() => (init_uuid(), uuid_exports));
|
|
4064
|
+
const id = generateUUID2();
|
|
4065
|
+
await nativeStorage.set(INSTALL_KEYS.INSTALL_EVENT_ID, id).catch(() => {
|
|
4066
|
+
});
|
|
4067
|
+
return id;
|
|
4068
|
+
}
|
|
4069
|
+
var INSTALL_KEYS;
|
|
4070
|
+
var init_InstallIdempotency = __esm({
|
|
4071
|
+
"src/domains/identity/InstallIdempotency.ts"() {
|
|
4072
|
+
"use strict";
|
|
4073
|
+
init_NativeStorage();
|
|
4074
|
+
INSTALL_KEYS = {
|
|
4075
|
+
/** Primary flag — set AFTER a successful $app_installed dispatch. */
|
|
4076
|
+
INSTALL_TRACKED: "@panel:install_tracked",
|
|
4077
|
+
/** Legacy fallback flag written by older SDK versions. */
|
|
4078
|
+
LEGACY_INSTALL_TRACKED: "@paywallo:install_tracked",
|
|
4079
|
+
/** Pre-send guard — set BEFORE dispatching to survive concurrent cold-starts. */
|
|
4080
|
+
INSTALL_SENT: "@paywallo:app_installed_sent",
|
|
4081
|
+
/** Stable event ID for backend dedup — generated once, reused on retries. */
|
|
4082
|
+
INSTALL_EVENT_ID: "@panel:install_event_id",
|
|
4083
|
+
/** Deferred match flag — set once iOS fingerprint match succeeds. */
|
|
4084
|
+
DEFERRED_MATCH_DONE: "@panel:deferred_match_done",
|
|
4085
|
+
/** Anonymous ID fallback when FB SDK not available. */
|
|
4086
|
+
ANON_ID: "@panel:anon_id"
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
});
|
|
4090
|
+
|
|
4091
|
+
// src/domains/identity/InstallReferrerManager.ts
|
|
4092
|
+
var import_react_native13, REFERRER_TIMEOUT_MS, InstallReferrerManager, installReferrerManager;
|
|
4093
|
+
var init_InstallReferrerManager = __esm({
|
|
4094
|
+
"src/domains/identity/InstallReferrerManager.ts"() {
|
|
4095
|
+
"use strict";
|
|
4096
|
+
import_react_native13 = require("react-native");
|
|
4097
|
+
init_NativeDeviceInfo();
|
|
4098
|
+
REFERRER_TIMEOUT_MS = 5e3;
|
|
4099
|
+
InstallReferrerManager = class {
|
|
4100
|
+
async getReferrer() {
|
|
4101
|
+
if (import_react_native13.Platform.OS !== "android") {
|
|
4102
|
+
return this.emptyResult();
|
|
4103
|
+
}
|
|
4104
|
+
let timerId;
|
|
4105
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
4106
|
+
timerId = setTimeout(() => resolve(this.emptyResult()), REFERRER_TIMEOUT_MS);
|
|
4107
|
+
});
|
|
4108
|
+
const fetchPromise = this.fetchReferrer();
|
|
4109
|
+
const result = await Promise.race([fetchPromise, timeoutPromise]);
|
|
4110
|
+
clearTimeout(timerId);
|
|
4111
|
+
return result;
|
|
4112
|
+
}
|
|
4113
|
+
async fetchReferrer() {
|
|
4114
|
+
try {
|
|
4115
|
+
const referrer = await nativeDeviceInfo.getInstallReferrer();
|
|
4116
|
+
if (!referrer) return this.emptyResult();
|
|
4117
|
+
const capped = referrer.slice(0, 2048);
|
|
4118
|
+
const params = this.parseReferrer(capped);
|
|
4119
|
+
return {
|
|
4120
|
+
rawReferrer: capped,
|
|
4121
|
+
trackingId: params["tracking_id"] || null,
|
|
4122
|
+
fbclid: params["fbclid"] || null,
|
|
4123
|
+
utmSource: params["utm_source"] || null,
|
|
4124
|
+
utmMedium: params["utm_medium"] || null,
|
|
4125
|
+
utmCampaign: params["utm_campaign"] || null
|
|
4126
|
+
};
|
|
4127
|
+
} catch {
|
|
4128
|
+
return this.emptyResult();
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
parseReferrer(referrer) {
|
|
4132
|
+
const result = {};
|
|
4133
|
+
for (const pair of referrer.split("&")) {
|
|
4134
|
+
const eqIndex = pair.indexOf("=");
|
|
4135
|
+
if (eqIndex === -1) continue;
|
|
4136
|
+
try {
|
|
4137
|
+
const key = decodeURIComponent(pair.slice(0, eqIndex).replace(/\+/g, " "));
|
|
4138
|
+
const raw = pair.slice(eqIndex + 1).replace(/\+/g, " ");
|
|
4139
|
+
const value = decodeURIComponent(raw);
|
|
4140
|
+
if (key) result[key] = value;
|
|
4141
|
+
} catch {
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
return result;
|
|
4145
|
+
}
|
|
4146
|
+
emptyResult() {
|
|
4147
|
+
return {
|
|
4148
|
+
rawReferrer: null,
|
|
4149
|
+
trackingId: null,
|
|
4150
|
+
fbclid: null,
|
|
4151
|
+
utmSource: null,
|
|
4152
|
+
utmMedium: null,
|
|
4153
|
+
utmCampaign: null
|
|
4154
|
+
};
|
|
4155
|
+
}
|
|
4156
|
+
};
|
|
4157
|
+
installReferrerManager = new InstallReferrerManager();
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
4160
|
+
|
|
4161
|
+
// src/domains/identity/MetaBridge.ts
|
|
4162
|
+
var import_react_native14, TIMEOUT_MS, NativeBridge, MetaBridge, metaBridge;
|
|
4163
|
+
var init_MetaBridge = __esm({
|
|
4164
|
+
"src/domains/identity/MetaBridge.ts"() {
|
|
4165
|
+
"use strict";
|
|
4166
|
+
import_react_native14 = require("react-native");
|
|
4167
|
+
TIMEOUT_MS = 2e3;
|
|
4168
|
+
NativeBridge = import_react_native14.NativeModules.PaywalloFBBridge ?? null;
|
|
4169
|
+
MetaBridge = class {
|
|
4170
|
+
constructor() {
|
|
4171
|
+
this.cachedAnonId = null;
|
|
4172
|
+
}
|
|
4173
|
+
/** Sync read of the cached anonymous ID. Returns null until `getAnonymousID()` resolves once. */
|
|
4174
|
+
getCachedAnonymousID() {
|
|
4175
|
+
return this.cachedAnonId;
|
|
4176
|
+
}
|
|
4177
|
+
async getAnonymousID() {
|
|
4178
|
+
if (this.cachedAnonId) return this.cachedAnonId;
|
|
4179
|
+
if (!NativeBridge) return null;
|
|
4180
|
+
try {
|
|
4181
|
+
let timerId;
|
|
4182
|
+
const timeout = new Promise((resolve) => {
|
|
4183
|
+
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
4184
|
+
});
|
|
4185
|
+
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
4186
|
+
clearTimeout(timerId);
|
|
4187
|
+
if (result) this.cachedAnonId = result;
|
|
4188
|
+
return result;
|
|
4189
|
+
} catch {
|
|
4190
|
+
return null;
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
async logEvent(name, params = {}) {
|
|
4194
|
+
if (!NativeBridge) return;
|
|
4195
|
+
try {
|
|
4196
|
+
await NativeBridge.logEvent(name, params);
|
|
4197
|
+
} catch (error) {
|
|
4198
|
+
console.warn("[Paywallo:MetaBridge] logEvent failed", { name, error });
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
async logPurchase(amount, currency, params = {}) {
|
|
4202
|
+
if (!NativeBridge) return;
|
|
4203
|
+
try {
|
|
4204
|
+
await NativeBridge.logPurchase(amount, currency, params);
|
|
4205
|
+
} catch (error) {
|
|
4206
|
+
console.warn("[Paywallo:MetaBridge] logPurchase failed", { amount, currency, error });
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
setUserID(userId) {
|
|
4210
|
+
if (!NativeBridge) return;
|
|
4211
|
+
try {
|
|
4212
|
+
NativeBridge.setUserID(userId);
|
|
4213
|
+
} catch (error) {
|
|
4214
|
+
console.warn("[Paywallo:MetaBridge] setUserID failed", { error });
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
flush() {
|
|
4218
|
+
if (!NativeBridge) return;
|
|
4219
|
+
try {
|
|
4220
|
+
NativeBridge.flush();
|
|
4221
|
+
} catch (error) {
|
|
4222
|
+
console.warn("[Paywallo:MetaBridge] flush failed", { error });
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
};
|
|
4226
|
+
metaBridge = new MetaBridge();
|
|
4227
|
+
}
|
|
4228
|
+
});
|
|
4229
|
+
|
|
4230
|
+
// src/domains/identity/InstallTracker.ts
|
|
4231
|
+
var import_react_native15, InstallTracker;
|
|
4232
|
+
var init_InstallTracker = __esm({
|
|
4233
|
+
"src/domains/identity/InstallTracker.ts"() {
|
|
4234
|
+
"use strict";
|
|
4235
|
+
import_react_native15 = require("react-native");
|
|
4236
|
+
init_SecureStorage();
|
|
4237
|
+
init_NativeDeviceInfo();
|
|
4089
4238
|
init_distinctIdGuard();
|
|
4239
|
+
init_SessionManager();
|
|
4240
|
+
init_AdvertisingIdManager();
|
|
4241
|
+
init_AttributionTracker();
|
|
4242
|
+
init_IdentityManager();
|
|
4090
4243
|
init_InstallIdempotency();
|
|
4244
|
+
init_InstallReferrerManager();
|
|
4245
|
+
init_MetaBridge();
|
|
4091
4246
|
init_AttributionTracker();
|
|
4092
4247
|
InstallTracker = class {
|
|
4093
4248
|
constructor(debug = false, optionsOrManager) {
|
|
@@ -4098,7 +4253,7 @@ var init_InstallTracker = __esm({
|
|
|
4098
4253
|
this.distinctIdProvider = () => identityManager.getDistinctId();
|
|
4099
4254
|
} else {
|
|
4100
4255
|
const opts = optionsOrManager ?? {};
|
|
4101
|
-
this.advertisingIdManager = opts.advertisingIdManager ??
|
|
4256
|
+
this.advertisingIdManager = opts.advertisingIdManager ?? advertisingIdManager;
|
|
4102
4257
|
this.distinctIdProvider = opts.distinctIdProvider ?? (() => identityManager.getDistinctId());
|
|
4103
4258
|
}
|
|
4104
4259
|
}
|
|
@@ -4136,6 +4291,7 @@ var init_InstallTracker = __esm({
|
|
|
4136
4291
|
const screen = import_react_native15.Dimensions.get("screen");
|
|
4137
4292
|
const screenWidth = Math.round(screen.width ?? 0);
|
|
4138
4293
|
const screenHeight = Math.round(screen.height ?? 0);
|
|
4294
|
+
const screenDensity = import_react_native15.PixelRatio.get();
|
|
4139
4295
|
const locale = Intl.DateTimeFormat().resolvedOptions().locale ?? "unknown";
|
|
4140
4296
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? "unknown";
|
|
4141
4297
|
const info = await nativeDeviceInfo.getDeviceInfo();
|
|
@@ -4182,6 +4338,7 @@ var init_InstallTracker = __esm({
|
|
|
4182
4338
|
buildNumber,
|
|
4183
4339
|
...screenWidth > 0 && { screenWidth },
|
|
4184
4340
|
...screenHeight > 0 && { screenHeight },
|
|
4341
|
+
...screenDensity > 0 && { screenDensity },
|
|
4185
4342
|
timezone,
|
|
4186
4343
|
locale,
|
|
4187
4344
|
...carrier !== "unknown" && { carrier },
|
|
@@ -4199,6 +4356,16 @@ var init_InstallTracker = __esm({
|
|
|
4199
4356
|
this.advertisingIdManager.collect(requestATT),
|
|
4200
4357
|
getOrCreateInstallEventId()
|
|
4201
4358
|
]);
|
|
4359
|
+
if (referrer.fbclid || referrer.utmSource || referrer.utmMedium || referrer.utmCampaign) {
|
|
4360
|
+
attributionTracker.capture({
|
|
4361
|
+
...referrer.fbclid && { fbclid: referrer.fbclid },
|
|
4362
|
+
...referrer.utmSource && { utmSource: referrer.utmSource },
|
|
4363
|
+
...referrer.utmMedium && { utmMedium: referrer.utmMedium },
|
|
4364
|
+
...referrer.utmCampaign && { utmCampaign: referrer.utmCampaign },
|
|
4365
|
+
...referrer.rawReferrer && { referrer: referrer.rawReferrer }
|
|
4366
|
+
}).catch(() => {
|
|
4367
|
+
});
|
|
4368
|
+
}
|
|
4202
4369
|
let effectiveAnonId = fbAnonId;
|
|
4203
4370
|
if (!effectiveAnonId) {
|
|
4204
4371
|
const stored = await storage.get(INSTALL_KEYS.ANON_ID);
|
|
@@ -4243,7 +4410,7 @@ var init_InstallTracker = __esm({
|
|
|
4243
4410
|
const baseUrl = apiClient.getBaseUrl();
|
|
4244
4411
|
const appKey = apiClient.getAppKey();
|
|
4245
4412
|
const referrer = await installReferrerManager.getReferrer();
|
|
4246
|
-
await fetch(`${baseUrl}/attribution/deferred-match/${appKey}`, {
|
|
4413
|
+
await fetch(`${baseUrl}/sdk/attribution/deferred-match/${appKey}`, {
|
|
4247
4414
|
method: "POST",
|
|
4248
4415
|
headers: { "Content-Type": "application/json", "X-App-Key": appKey },
|
|
4249
4416
|
body: JSON.stringify({
|
|
@@ -4374,6 +4541,9 @@ var init_identity = __esm({
|
|
|
4374
4541
|
});
|
|
4375
4542
|
|
|
4376
4543
|
// src/domains/notifications/bridges/NativePushBridge.ts
|
|
4544
|
+
function isNativePushAvailable() {
|
|
4545
|
+
return !!import_react_native17.NativeModules.PaywalloNotifications;
|
|
4546
|
+
}
|
|
4377
4547
|
function mapStatusToNumber(status) {
|
|
4378
4548
|
switch (status) {
|
|
4379
4549
|
case "granted":
|
|
@@ -5038,8 +5208,8 @@ var init_utils = __esm({
|
|
|
5038
5208
|
// src/core/version.ts
|
|
5039
5209
|
function resolveVersion() {
|
|
5040
5210
|
try {
|
|
5041
|
-
if ("2.1
|
|
5042
|
-
return "2.1
|
|
5211
|
+
if ("2.2.1") {
|
|
5212
|
+
return "2.2.1";
|
|
5043
5213
|
}
|
|
5044
5214
|
} catch {
|
|
5045
5215
|
}
|
|
@@ -5121,7 +5291,7 @@ var init_TokenRegistration = __esm({
|
|
|
5121
5291
|
init_utils();
|
|
5122
5292
|
init_version();
|
|
5123
5293
|
FCM_TOKEN_KEY = "@panel:push_token";
|
|
5124
|
-
TOKEN_ENDPOINT = "/push-tokens";
|
|
5294
|
+
TOKEN_ENDPOINT = "/sdk/push-tokens";
|
|
5125
5295
|
}
|
|
5126
5296
|
});
|
|
5127
5297
|
|
|
@@ -5413,58 +5583,400 @@ var init_NotificationsManager = __esm({
|
|
|
5413
5583
|
this.currentToken = null;
|
|
5414
5584
|
}
|
|
5415
5585
|
};
|
|
5416
|
-
notificationsManager = new NotificationsManager();
|
|
5586
|
+
notificationsManager = new NotificationsManager();
|
|
5587
|
+
}
|
|
5588
|
+
});
|
|
5589
|
+
|
|
5590
|
+
// src/domains/notifications/index.ts
|
|
5591
|
+
var init_notifications = __esm({
|
|
5592
|
+
"src/domains/notifications/index.ts"() {
|
|
5593
|
+
"use strict";
|
|
5594
|
+
init_NotificationsManager();
|
|
5595
|
+
init_NativePushBridge();
|
|
5596
|
+
init_NotificationsError();
|
|
5597
|
+
}
|
|
5598
|
+
});
|
|
5599
|
+
|
|
5600
|
+
// src/domains/session/index.ts
|
|
5601
|
+
var init_session = __esm({
|
|
5602
|
+
"src/domains/session/index.ts"() {
|
|
5603
|
+
"use strict";
|
|
5604
|
+
init_SessionManager();
|
|
5605
|
+
init_SessionError();
|
|
5606
|
+
}
|
|
5607
|
+
});
|
|
5608
|
+
|
|
5609
|
+
// src/core/PaywalloState.ts
|
|
5610
|
+
function createPaywalloState() {
|
|
5611
|
+
return {
|
|
5612
|
+
config: null,
|
|
5613
|
+
apiClient: null,
|
|
5614
|
+
initPromise: null,
|
|
5615
|
+
readyPromise: null,
|
|
5616
|
+
resolveReady: null,
|
|
5617
|
+
paywallPresenter: null,
|
|
5618
|
+
campaignPresenter: null,
|
|
5619
|
+
subscriptionGetter: null,
|
|
5620
|
+
activeChecker: null,
|
|
5621
|
+
restoreHandler: null,
|
|
5622
|
+
lastOnboardingStepTimestamp: null,
|
|
5623
|
+
pendingConfig: null,
|
|
5624
|
+
networkCleanup: null,
|
|
5625
|
+
initAttempts: 0,
|
|
5626
|
+
autoPreloadedPlacement: null,
|
|
5627
|
+
autoPreloadPlacementPromise: null,
|
|
5628
|
+
sessionFlagsMap: /* @__PURE__ */ new Map(),
|
|
5629
|
+
pendingIdentifies: []
|
|
5630
|
+
};
|
|
5631
|
+
}
|
|
5632
|
+
var MAX_INIT_RETRIES, RETRY_DELAYS;
|
|
5633
|
+
var init_PaywalloState = __esm({
|
|
5634
|
+
"src/core/PaywalloState.ts"() {
|
|
5635
|
+
"use strict";
|
|
5636
|
+
MAX_INIT_RETRIES = 3;
|
|
5637
|
+
RETRY_DELAYS = [2e3, 5e3, 1e4];
|
|
5638
|
+
}
|
|
5639
|
+
});
|
|
5640
|
+
|
|
5641
|
+
// src/domains/plan/PlanCache.ts
|
|
5642
|
+
var DEFAULT_TTL, PlanCache, planCache;
|
|
5643
|
+
var init_PlanCache = __esm({
|
|
5644
|
+
"src/domains/plan/PlanCache.ts"() {
|
|
5645
|
+
"use strict";
|
|
5646
|
+
DEFAULT_TTL = 5 * 60 * 1e3;
|
|
5647
|
+
PlanCache = class {
|
|
5648
|
+
constructor() {
|
|
5649
|
+
this.cache = null;
|
|
5650
|
+
this.ttl = DEFAULT_TTL;
|
|
5651
|
+
}
|
|
5652
|
+
get() {
|
|
5653
|
+
if (!this.cache) return null;
|
|
5654
|
+
const isStale = Date.now() - this.cache.cachedAt > this.ttl;
|
|
5655
|
+
return { ...this.cache, isStale };
|
|
5656
|
+
}
|
|
5657
|
+
set(data) {
|
|
5658
|
+
this.cache = { data, cachedAt: Date.now(), isStale: false };
|
|
5659
|
+
}
|
|
5660
|
+
invalidate() {
|
|
5661
|
+
this.cache = null;
|
|
5662
|
+
}
|
|
5663
|
+
setTTL(ttl) {
|
|
5664
|
+
this.ttl = ttl;
|
|
5665
|
+
}
|
|
5666
|
+
};
|
|
5667
|
+
planCache = new PlanCache();
|
|
5668
|
+
}
|
|
5669
|
+
});
|
|
5670
|
+
|
|
5671
|
+
// src/domains/plan/PlanError.ts
|
|
5672
|
+
var PlanError, PLAN_ERROR_CODES;
|
|
5673
|
+
var init_PlanError = __esm({
|
|
5674
|
+
"src/domains/plan/PlanError.ts"() {
|
|
5675
|
+
"use strict";
|
|
5676
|
+
init_PaywalloError();
|
|
5677
|
+
PlanError = class extends PaywalloError {
|
|
5678
|
+
constructor(code, message) {
|
|
5679
|
+
super("plan", code, message);
|
|
5680
|
+
this.name = "PlanError";
|
|
5681
|
+
}
|
|
5682
|
+
};
|
|
5683
|
+
PLAN_ERROR_CODES = {
|
|
5684
|
+
NOT_INITIALIZED: "PLAN_NOT_INITIALIZED",
|
|
5685
|
+
FETCH_FAILED: "PLAN_FETCH_FAILED"
|
|
5686
|
+
};
|
|
5687
|
+
}
|
|
5688
|
+
});
|
|
5689
|
+
|
|
5690
|
+
// src/domains/plan/PlanService.ts
|
|
5691
|
+
var PlanService_exports = {};
|
|
5692
|
+
__export(PlanService_exports, {
|
|
5693
|
+
PlanService: () => PlanService,
|
|
5694
|
+
planService: () => planService
|
|
5695
|
+
});
|
|
5696
|
+
function mapProduct(raw) {
|
|
5697
|
+
return {
|
|
5698
|
+
id: raw.id,
|
|
5699
|
+
name: raw.name,
|
|
5700
|
+
description: raw.description,
|
|
5701
|
+
type: raw.type,
|
|
5702
|
+
appleProductId: raw.apple_product_id,
|
|
5703
|
+
googleProductId: raw.google_product_id,
|
|
5704
|
+
billingPeriod: raw.billing_period,
|
|
5705
|
+
trialDays: raw.trial_days,
|
|
5706
|
+
priceUsd: raw.price_usd,
|
|
5707
|
+
regionalPrices: raw.regional_prices,
|
|
5708
|
+
displayOrder: raw.display_order,
|
|
5709
|
+
isActive: raw.is_active
|
|
5710
|
+
};
|
|
5711
|
+
}
|
|
5712
|
+
function mapPlan(raw) {
|
|
5713
|
+
return {
|
|
5714
|
+
id: raw.id,
|
|
5715
|
+
identifier: raw.identifier,
|
|
5716
|
+
name: raw.name,
|
|
5717
|
+
description: raw.description,
|
|
5718
|
+
metadata: raw.metadata,
|
|
5719
|
+
products: raw.products.map(mapProduct)
|
|
5720
|
+
};
|
|
5721
|
+
}
|
|
5722
|
+
var PlanService, planService;
|
|
5723
|
+
var init_PlanService = __esm({
|
|
5724
|
+
"src/domains/plan/PlanService.ts"() {
|
|
5725
|
+
"use strict";
|
|
5726
|
+
init_PlanCache();
|
|
5727
|
+
init_PlanError();
|
|
5728
|
+
PlanService = class {
|
|
5729
|
+
constructor() {
|
|
5730
|
+
this.config = null;
|
|
5731
|
+
this.cache = planCache;
|
|
5732
|
+
}
|
|
5733
|
+
init(config) {
|
|
5734
|
+
this.config = config;
|
|
5735
|
+
}
|
|
5736
|
+
async getCurrentPlan(forceRefresh = false) {
|
|
5737
|
+
if (!forceRefresh) {
|
|
5738
|
+
const cached = this.cache.get();
|
|
5739
|
+
if (cached && !cached.isStale) {
|
|
5740
|
+
const current = cached.data.plans.find(
|
|
5741
|
+
(p) => p.identifier === cached.data.currentIdentifier
|
|
5742
|
+
);
|
|
5743
|
+
return current ?? null;
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
return this.fetchCurrentPlan();
|
|
5747
|
+
}
|
|
5748
|
+
async getAllPlans(forceRefresh = false) {
|
|
5749
|
+
if (!forceRefresh) {
|
|
5750
|
+
const cached = this.cache.get();
|
|
5751
|
+
if (cached && !cached.isStale) return cached.data;
|
|
5752
|
+
}
|
|
5753
|
+
return this.fetchAllPlans();
|
|
5754
|
+
}
|
|
5755
|
+
invalidateCache() {
|
|
5756
|
+
this.cache.invalidate();
|
|
5757
|
+
}
|
|
5758
|
+
getApiClient() {
|
|
5759
|
+
if (!this.config) {
|
|
5760
|
+
throw new PlanError(PLAN_ERROR_CODES.NOT_INITIALIZED, "PlanService not initialized. Call Paywallo.init() first");
|
|
5761
|
+
}
|
|
5762
|
+
return this.config.apiClient;
|
|
5763
|
+
}
|
|
5764
|
+
async fetchCurrentPlan() {
|
|
5765
|
+
try {
|
|
5766
|
+
const res = await this.getApiClient().get("/sdk/plans");
|
|
5767
|
+
if (!res.ok) {
|
|
5768
|
+
this.log("fetchCurrentPlan failed", res.status);
|
|
5769
|
+
return null;
|
|
5770
|
+
}
|
|
5771
|
+
const raw = res.data.data.plan;
|
|
5772
|
+
return raw ? mapPlan(raw) : null;
|
|
5773
|
+
} catch (err) {
|
|
5774
|
+
this.log("fetchCurrentPlan error", err);
|
|
5775
|
+
return null;
|
|
5776
|
+
}
|
|
5777
|
+
}
|
|
5778
|
+
async fetchAllPlans() {
|
|
5779
|
+
try {
|
|
5780
|
+
const res = await this.getApiClient().get("/sdk/plans/all");
|
|
5781
|
+
if (!res.ok) {
|
|
5782
|
+
this.log("fetchAllPlans failed", res.status);
|
|
5783
|
+
return { plans: [], currentIdentifier: null };
|
|
5784
|
+
}
|
|
5785
|
+
const result = {
|
|
5786
|
+
plans: res.data.data.plans.map(mapPlan),
|
|
5787
|
+
currentIdentifier: res.data.data.current_identifier
|
|
5788
|
+
};
|
|
5789
|
+
this.cache.set(result);
|
|
5790
|
+
return result;
|
|
5791
|
+
} catch (err) {
|
|
5792
|
+
this.log("fetchAllPlans error", err);
|
|
5793
|
+
return { plans: [], currentIdentifier: null };
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5796
|
+
log(...args) {
|
|
5797
|
+
if (this.config?.debug) console.log("[Paywallo Plans]", ...args);
|
|
5798
|
+
}
|
|
5799
|
+
};
|
|
5800
|
+
planService = new PlanService();
|
|
5801
|
+
}
|
|
5802
|
+
});
|
|
5803
|
+
|
|
5804
|
+
// src/domains/plan/index.ts
|
|
5805
|
+
var init_plan = __esm({
|
|
5806
|
+
"src/domains/plan/index.ts"() {
|
|
5807
|
+
"use strict";
|
|
5808
|
+
init_PlanCache();
|
|
5809
|
+
init_PlanService();
|
|
5810
|
+
}
|
|
5811
|
+
});
|
|
5812
|
+
|
|
5813
|
+
// src/domains/onboarding/OnboardingError.ts
|
|
5814
|
+
var OnboardingError, ONBOARDING_ERROR_CODES;
|
|
5815
|
+
var init_OnboardingError = __esm({
|
|
5816
|
+
"src/domains/onboarding/OnboardingError.ts"() {
|
|
5817
|
+
"use strict";
|
|
5818
|
+
init_PaywalloError();
|
|
5819
|
+
OnboardingError = class extends PaywalloError {
|
|
5820
|
+
constructor(code, message) {
|
|
5821
|
+
super("onboarding", code, message);
|
|
5822
|
+
this.name = "OnboardingError";
|
|
5823
|
+
}
|
|
5824
|
+
};
|
|
5825
|
+
ONBOARDING_ERROR_CODES = {
|
|
5826
|
+
NOT_INITIALIZED: "ONBOARDING_NOT_INITIALIZED",
|
|
5827
|
+
INVALID_STEP_NAME: "ONBOARDING_INVALID_STEP_NAME"
|
|
5828
|
+
};
|
|
5829
|
+
}
|
|
5830
|
+
});
|
|
5831
|
+
|
|
5832
|
+
// src/domains/onboarding/OnboardingManager.ts
|
|
5833
|
+
var OnboardingManager, onboardingManager;
|
|
5834
|
+
var init_OnboardingManager = __esm({
|
|
5835
|
+
"src/domains/onboarding/OnboardingManager.ts"() {
|
|
5836
|
+
"use strict";
|
|
5837
|
+
init_OnboardingError();
|
|
5838
|
+
OnboardingManager = class {
|
|
5839
|
+
constructor() {
|
|
5840
|
+
this.pipeline = null;
|
|
5841
|
+
this.debug = false;
|
|
5842
|
+
this.lastStep = null;
|
|
5843
|
+
this.finished = false;
|
|
5844
|
+
}
|
|
5845
|
+
/**
|
|
5846
|
+
* Injects runtime dependencies. Called by PaywalloClient during init.
|
|
5847
|
+
*/
|
|
5848
|
+
injectDeps(config) {
|
|
5849
|
+
this.pipeline = config.pipeline;
|
|
5850
|
+
this.debug = config.debug ?? false;
|
|
5851
|
+
}
|
|
5852
|
+
/**
|
|
5853
|
+
* Tracks an onboarding step view.
|
|
5854
|
+
* Saves the step name internally for implicit drop detection on the backend.
|
|
5855
|
+
*
|
|
5856
|
+
* @param stepName - Unique name for this onboarding step.
|
|
5857
|
+
*/
|
|
5858
|
+
async step(stepName) {
|
|
5859
|
+
this.assertConfig();
|
|
5860
|
+
this.validateStepName(stepName, "step");
|
|
5861
|
+
this.lastStep = stepName;
|
|
5862
|
+
const payload = {
|
|
5863
|
+
family: "onboarding",
|
|
5864
|
+
type: "step",
|
|
5865
|
+
...{ step_name: stepName }
|
|
5866
|
+
};
|
|
5867
|
+
return this.emit("onboarding", payload, "step");
|
|
5868
|
+
}
|
|
5869
|
+
/**
|
|
5870
|
+
* Tracks successful completion of the onboarding flow.
|
|
5871
|
+
* Marks the flow as finished.
|
|
5872
|
+
*/
|
|
5873
|
+
async complete() {
|
|
5874
|
+
this.assertConfig();
|
|
5875
|
+
this.finished = true;
|
|
5876
|
+
return this.emit("onboarding", { family: "onboarding", type: "complete" }, "complete");
|
|
5877
|
+
}
|
|
5878
|
+
/**
|
|
5879
|
+
* Tracks an explicit drop (abandonment) at the given step.
|
|
5880
|
+
* Marks the flow as finished.
|
|
5881
|
+
*
|
|
5882
|
+
* @param stepName - The step name where the user dropped off.
|
|
5883
|
+
*/
|
|
5884
|
+
async drop(stepName) {
|
|
5885
|
+
this.assertConfig();
|
|
5886
|
+
this.validateStepName(stepName, "drop");
|
|
5887
|
+
this.finished = true;
|
|
5888
|
+
const payload = {
|
|
5889
|
+
family: "onboarding",
|
|
5890
|
+
type: "drop",
|
|
5891
|
+
...{ step_name: stepName }
|
|
5892
|
+
};
|
|
5893
|
+
return this.emit("onboarding", payload, "drop");
|
|
5894
|
+
}
|
|
5895
|
+
/** Returns the last step name seen, or null if no step was tracked yet. */
|
|
5896
|
+
getLastStep() {
|
|
5897
|
+
return this.lastStep;
|
|
5898
|
+
}
|
|
5899
|
+
/** Returns whether the flow has been marked as finished (complete or drop). */
|
|
5900
|
+
isFinished() {
|
|
5901
|
+
return this.finished;
|
|
5902
|
+
}
|
|
5903
|
+
async emit(eventName, properties, logLabel) {
|
|
5904
|
+
const pipeline = this.pipeline;
|
|
5905
|
+
const distinctId = pipeline.getDistinctId();
|
|
5906
|
+
if (!distinctId) {
|
|
5907
|
+
if (this.debug) console.log(`[Paywallo:Onboarding] skipped (no distinctId): ${logLabel}`);
|
|
5908
|
+
return;
|
|
5909
|
+
}
|
|
5910
|
+
await pipeline.trackEvent(eventName, distinctId, properties);
|
|
5911
|
+
if (this.debug) {
|
|
5912
|
+
console.log(`[Paywallo:Onboarding] event emitted: ${eventName}.${logLabel}`, properties);
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
assertConfig() {
|
|
5916
|
+
if (!this.pipeline) {
|
|
5917
|
+
throw new OnboardingError(
|
|
5918
|
+
ONBOARDING_ERROR_CODES.NOT_INITIALIZED,
|
|
5919
|
+
"OnboardingManager not initialized. Call Paywallo.init() first."
|
|
5920
|
+
);
|
|
5921
|
+
}
|
|
5922
|
+
}
|
|
5923
|
+
validateStepName(stepName, method) {
|
|
5924
|
+
if (typeof stepName !== "string" || stepName.trim().length === 0) {
|
|
5925
|
+
throw new OnboardingError(
|
|
5926
|
+
ONBOARDING_ERROR_CODES.INVALID_STEP_NAME,
|
|
5927
|
+
`OnboardingManager.${method}(): stepName must be a non-empty string.`
|
|
5928
|
+
);
|
|
5929
|
+
}
|
|
5930
|
+
}
|
|
5931
|
+
};
|
|
5932
|
+
onboardingManager = new OnboardingManager();
|
|
5417
5933
|
}
|
|
5418
5934
|
});
|
|
5419
5935
|
|
|
5420
|
-
// src/domains/
|
|
5421
|
-
var
|
|
5422
|
-
"src/domains/
|
|
5936
|
+
// src/domains/onboarding/index.ts
|
|
5937
|
+
var init_onboarding = __esm({
|
|
5938
|
+
"src/domains/onboarding/index.ts"() {
|
|
5423
5939
|
"use strict";
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
init_NotificationsError();
|
|
5940
|
+
init_OnboardingManager();
|
|
5941
|
+
init_OnboardingError();
|
|
5427
5942
|
}
|
|
5428
5943
|
});
|
|
5429
5944
|
|
|
5430
|
-
// src/domains/
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5945
|
+
// src/domains/paywall/paywallHeartbeatRecovery.ts
|
|
5946
|
+
async function recoverPaywallHeartbeat(apiClient, distinctId, sessionId, debug) {
|
|
5947
|
+
const snapshot = await readPersistedHeartbeat();
|
|
5948
|
+
if (!snapshot) return false;
|
|
5949
|
+
try {
|
|
5950
|
+
const closedAt = new Date(snapshot.lastSeen);
|
|
5951
|
+
const durationS = Math.max(0, Math.round((snapshot.lastSeen - snapshot.presentedAt) / 1e3));
|
|
5952
|
+
await apiClient.trackEvent("paywall", distinctId, {
|
|
5953
|
+
type: "closed",
|
|
5954
|
+
paywall_id: snapshot.paywallId,
|
|
5955
|
+
placement: snapshot.placement,
|
|
5956
|
+
closed_at: closedAt.toISOString(),
|
|
5957
|
+
duration_s: durationS,
|
|
5958
|
+
close_reason: "error",
|
|
5959
|
+
...snapshot.variantId && { variant_id: snapshot.variantId },
|
|
5960
|
+
...snapshot.variantKey && { variant_key: snapshot.variantKey },
|
|
5961
|
+
...snapshot.campaignId && { campaign_id: snapshot.campaignId },
|
|
5962
|
+
...sessionId && { sessionId }
|
|
5963
|
+
});
|
|
5964
|
+
if (debug) console.log("[Paywallo HEARTBEAT] recovered orphan paywall close", {
|
|
5965
|
+
paywallId: snapshot.paywallId,
|
|
5966
|
+
durationS
|
|
5967
|
+
});
|
|
5968
|
+
return true;
|
|
5969
|
+
} catch (err) {
|
|
5970
|
+
if (debug) console.log("[Paywallo HEARTBEAT] recovery failed", err);
|
|
5971
|
+
return false;
|
|
5972
|
+
} finally {
|
|
5973
|
+
await clearPersistedHeartbeat();
|
|
5436
5974
|
}
|
|
5437
|
-
});
|
|
5438
|
-
|
|
5439
|
-
// src/core/PaywalloState.ts
|
|
5440
|
-
function createPaywalloState() {
|
|
5441
|
-
return {
|
|
5442
|
-
config: null,
|
|
5443
|
-
apiClient: null,
|
|
5444
|
-
initPromise: null,
|
|
5445
|
-
readyPromise: null,
|
|
5446
|
-
resolveReady: null,
|
|
5447
|
-
paywallPresenter: null,
|
|
5448
|
-
campaignPresenter: null,
|
|
5449
|
-
subscriptionGetter: null,
|
|
5450
|
-
activeChecker: null,
|
|
5451
|
-
restoreHandler: null,
|
|
5452
|
-
lastOnboardingStepTimestamp: null,
|
|
5453
|
-
pendingConfig: null,
|
|
5454
|
-
networkCleanup: null,
|
|
5455
|
-
initAttempts: 0,
|
|
5456
|
-
autoPreloadedPlacement: null,
|
|
5457
|
-
autoPreloadPlacementPromise: null,
|
|
5458
|
-
sessionFlagsMap: /* @__PURE__ */ new Map(),
|
|
5459
|
-
pendingIdentifies: []
|
|
5460
|
-
};
|
|
5461
5975
|
}
|
|
5462
|
-
var
|
|
5463
|
-
|
|
5464
|
-
"src/core/PaywalloState.ts"() {
|
|
5976
|
+
var init_paywallHeartbeatRecovery = __esm({
|
|
5977
|
+
"src/domains/paywall/paywallHeartbeatRecovery.ts"() {
|
|
5465
5978
|
"use strict";
|
|
5466
|
-
|
|
5467
|
-
RETRY_DELAYS = [2e3, 5e3, 1e4];
|
|
5979
|
+
init_paywallHeartbeat();
|
|
5468
5980
|
}
|
|
5469
5981
|
});
|
|
5470
5982
|
|
|
@@ -5472,7 +5984,7 @@ var init_PaywalloState = __esm({
|
|
|
5472
5984
|
function keyFor(distinctId) {
|
|
5473
5985
|
return `${CACHE_KEY_PREFIX}${distinctId}`;
|
|
5474
5986
|
}
|
|
5475
|
-
var LEGACY_CACHE_KEY, CACHE_KEY_PREFIX, CACHE_INDEX_KEY,
|
|
5987
|
+
var LEGACY_CACHE_KEY, CACHE_KEY_PREFIX, CACHE_INDEX_KEY, DEFAULT_TTL2, SubscriptionCache, subscriptionCache;
|
|
5476
5988
|
var init_SubscriptionCache = __esm({
|
|
5477
5989
|
"src/domains/subscription/SubscriptionCache.ts"() {
|
|
5478
5990
|
"use strict";
|
|
@@ -5480,9 +5992,9 @@ var init_SubscriptionCache = __esm({
|
|
|
5480
5992
|
LEGACY_CACHE_KEY = "@panel:subscription_cache";
|
|
5481
5993
|
CACHE_KEY_PREFIX = "subscription_cache:";
|
|
5482
5994
|
CACHE_INDEX_KEY = "subscription_cache:__index__";
|
|
5483
|
-
|
|
5995
|
+
DEFAULT_TTL2 = 24 * 60 * 60 * 1e3;
|
|
5484
5996
|
SubscriptionCache = class {
|
|
5485
|
-
constructor(ttl =
|
|
5997
|
+
constructor(ttl = DEFAULT_TTL2) {
|
|
5486
5998
|
this.memoryCache = /* @__PURE__ */ new Map();
|
|
5487
5999
|
this.legacyCleanupDone = false;
|
|
5488
6000
|
this.ttl = ttl;
|
|
@@ -5689,7 +6201,7 @@ var init_SubscriptionManager = __esm({
|
|
|
5689
6201
|
if (!this.config) {
|
|
5690
6202
|
return this.getEmptyStatus();
|
|
5691
6203
|
}
|
|
5692
|
-
const url = new URL(`${this.config.serverUrl}/purchases/status/${this.config.appKey}`);
|
|
6204
|
+
const url = new URL(`${this.config.serverUrl}/sdk/purchases/status/${this.config.appKey}`);
|
|
5693
6205
|
if (this.userId) {
|
|
5694
6206
|
url.searchParams.set("distinctId", this.userId);
|
|
5695
6207
|
}
|
|
@@ -5929,7 +6441,7 @@ async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
|
|
|
5929
6441
|
}
|
|
5930
6442
|
async function getEmergencyPaywall(client) {
|
|
5931
6443
|
try {
|
|
5932
|
-
const response = await client.get("/emergency-paywall");
|
|
6444
|
+
const response = await client.get("/sdk/emergency-paywall");
|
|
5933
6445
|
if (response.status === 404) return { enabled: false };
|
|
5934
6446
|
return response.data;
|
|
5935
6447
|
} catch {
|
|
@@ -6546,7 +7058,7 @@ var init_EventBatcher = __esm({
|
|
|
6546
7058
|
BATCH_MAX_SIZE = 25;
|
|
6547
7059
|
BATCH_FLUSH_MS = 1e4;
|
|
6548
7060
|
EVENT_NAME_REGEX = /^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/;
|
|
6549
|
-
V2_BATCH_ENDPOINT = "/ingest/batch";
|
|
7061
|
+
V2_BATCH_ENDPOINT = "/sdk/ingest/batch";
|
|
6550
7062
|
V1_BATCH_ENDPOINT = "/sdk/events/batch";
|
|
6551
7063
|
V1_SINGLE_ENDPOINT = "/sdk/events";
|
|
6552
7064
|
EventBatcher = class {
|
|
@@ -6910,7 +7422,7 @@ var init_ApiClient = __esm({
|
|
|
6910
7422
|
dispose() {
|
|
6911
7423
|
this.batcher.dispose();
|
|
6912
7424
|
}
|
|
6913
|
-
async identify(distinctId, properties, email, deviceId) {
|
|
7425
|
+
async identify(distinctId, properties, email, deviceId, pii) {
|
|
6914
7426
|
await postWithQueue(
|
|
6915
7427
|
{
|
|
6916
7428
|
isOfflineQueueEnabled: () => this.offlineQueueEnabled,
|
|
@@ -6918,8 +7430,19 @@ var init_ApiClient = __esm({
|
|
|
6918
7430
|
isDebug: () => this.debug,
|
|
6919
7431
|
post: (path, body, skipRetry) => this.post(path, body, skipRetry)
|
|
6920
7432
|
},
|
|
6921
|
-
"/identify",
|
|
6922
|
-
{
|
|
7433
|
+
"/sdk/identify",
|
|
7434
|
+
{
|
|
7435
|
+
distinctId,
|
|
7436
|
+
properties: properties ?? {},
|
|
7437
|
+
email,
|
|
7438
|
+
platform: import_react_native23.Platform.OS,
|
|
7439
|
+
...deviceId && { deviceId },
|
|
7440
|
+
...pii?.phone && { phone: pii.phone },
|
|
7441
|
+
...pii?.firstName && { firstName: pii.firstName },
|
|
7442
|
+
...pii?.lastName && { lastName: pii.lastName },
|
|
7443
|
+
...pii?.dateOfBirth && { dateOfBirth: pii.dateOfBirth },
|
|
7444
|
+
...pii?.gender && { gender: pii.gender }
|
|
7445
|
+
},
|
|
6923
7446
|
"identify"
|
|
6924
7447
|
);
|
|
6925
7448
|
}
|
|
@@ -6946,246 +7469,85 @@ var init_ApiClient = __esm({
|
|
|
6946
7469
|
this.cache.setPaywall(placement, res.data);
|
|
6947
7470
|
return res.data;
|
|
6948
7471
|
} catch {
|
|
6949
|
-
const stale = this.cache.getStalePaywall(placement);
|
|
6950
|
-
return stale !== void 0 ? stale : null;
|
|
6951
|
-
}
|
|
6952
|
-
}
|
|
6953
|
-
async getEmergencyPaywall() {
|
|
6954
|
-
return getEmergencyPaywall(this);
|
|
6955
|
-
}
|
|
6956
|
-
async getCampaign(placement, distinctId, context) {
|
|
6957
|
-
const key = `${placement}:${distinctId}`;
|
|
6958
|
-
const hit = this.cache.getCampaign(key);
|
|
6959
|
-
if (hit !== void 0) return hit;
|
|
6960
|
-
try {
|
|
6961
|
-
const result = await getCampaignData(this, this.baseUrl, placement, distinctId, context);
|
|
6962
|
-
if (!result) {
|
|
6963
|
-
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
6964
|
-
return null;
|
|
6965
|
-
}
|
|
6966
|
-
this.cache.setCampaign(key, result);
|
|
6967
|
-
return result;
|
|
6968
|
-
} catch {
|
|
6969
|
-
const stale = this.cache.getStaleCampaign(key);
|
|
6970
|
-
return stale !== void 0 ? stale : null;
|
|
6971
|
-
}
|
|
6972
|
-
}
|
|
6973
|
-
async getPrimaryCampaign(distinctId) {
|
|
6974
|
-
const key = `primary:${distinctId}`;
|
|
6975
|
-
const hit = this.cache.getCampaign(key);
|
|
6976
|
-
if (hit !== void 0) return hit;
|
|
6977
|
-
try {
|
|
6978
|
-
const res = await this.get(`/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
6979
|
-
if (res.status === 404) {
|
|
6980
|
-
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
6981
|
-
return null;
|
|
6982
|
-
}
|
|
6983
|
-
if (!res.ok) {
|
|
6984
|
-
const stale = this.cache.getStaleCampaign(key);
|
|
6985
|
-
return stale !== void 0 ? stale : null;
|
|
6986
|
-
}
|
|
6987
|
-
this.cache.setCampaign(key, res.data);
|
|
6988
|
-
return res.data;
|
|
6989
|
-
} catch {
|
|
6990
|
-
const stale = this.cache.getStaleCampaign(key);
|
|
6991
|
-
return stale !== void 0 ? stale : null;
|
|
6992
|
-
}
|
|
6993
|
-
}
|
|
6994
|
-
async validatePurchase(platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey) {
|
|
6995
|
-
return validatePurchase(this, this.appKey, platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey);
|
|
6996
|
-
}
|
|
6997
|
-
async getSubscriptionStatus(distinctId) {
|
|
6998
|
-
return getSubscriptionStatus(this, this.baseUrl, this.appKey, distinctId);
|
|
6999
|
-
}
|
|
7000
|
-
async evaluateFlags(keys, distinctId) {
|
|
7001
|
-
return evaluateFlags(this.flagDeps(), keys, distinctId);
|
|
7002
|
-
}
|
|
7003
|
-
async getConditionalFlag(flagKey, context) {
|
|
7004
|
-
return getConditionalFlag(this.flagDeps(), flagKey, context);
|
|
7005
|
-
}
|
|
7006
|
-
async getVariantFromCache(flagKey, distinctId) {
|
|
7007
|
-
return getVariantFromCache(this.flagDeps(), flagKey, distinctId);
|
|
7008
|
-
}
|
|
7009
|
-
flagDeps() {
|
|
7010
|
-
return {
|
|
7011
|
-
get: (path) => this.get(path),
|
|
7012
|
-
httpClient: this.httpClient,
|
|
7013
|
-
cache: this.cache,
|
|
7014
|
-
appKey: this.appKey,
|
|
7015
|
-
baseUrl: this.baseUrl
|
|
7016
|
-
};
|
|
7017
|
-
}
|
|
7018
|
-
};
|
|
7019
|
-
}
|
|
7020
|
-
});
|
|
7021
|
-
|
|
7022
|
-
// src/domains/onboarding/OnboardingError.ts
|
|
7023
|
-
var OnboardingError, ONBOARDING_ERROR_CODES;
|
|
7024
|
-
var init_OnboardingError = __esm({
|
|
7025
|
-
"src/domains/onboarding/OnboardingError.ts"() {
|
|
7026
|
-
"use strict";
|
|
7027
|
-
init_PaywalloError();
|
|
7028
|
-
OnboardingError = class extends PaywalloError {
|
|
7029
|
-
constructor(code, message) {
|
|
7030
|
-
super("onboarding", code, message);
|
|
7031
|
-
this.name = "OnboardingError";
|
|
7032
|
-
}
|
|
7033
|
-
};
|
|
7034
|
-
ONBOARDING_ERROR_CODES = {
|
|
7035
|
-
NOT_INITIALIZED: "ONBOARDING_NOT_INITIALIZED",
|
|
7036
|
-
INVALID_STEP_NAME: "ONBOARDING_INVALID_STEP_NAME"
|
|
7037
|
-
};
|
|
7038
|
-
}
|
|
7039
|
-
});
|
|
7040
|
-
|
|
7041
|
-
// src/domains/onboarding/OnboardingManager.ts
|
|
7042
|
-
var OnboardingManager, onboardingManager;
|
|
7043
|
-
var init_OnboardingManager = __esm({
|
|
7044
|
-
"src/domains/onboarding/OnboardingManager.ts"() {
|
|
7045
|
-
"use strict";
|
|
7046
|
-
init_OnboardingError();
|
|
7047
|
-
OnboardingManager = class {
|
|
7048
|
-
constructor() {
|
|
7049
|
-
this.pipeline = null;
|
|
7050
|
-
this.debug = false;
|
|
7051
|
-
this.lastStep = null;
|
|
7052
|
-
this.finished = false;
|
|
7053
|
-
}
|
|
7054
|
-
/**
|
|
7055
|
-
* Injects runtime dependencies. Called by PaywalloClient during init.
|
|
7056
|
-
*/
|
|
7057
|
-
injectDeps(config) {
|
|
7058
|
-
this.pipeline = config.pipeline;
|
|
7059
|
-
this.debug = config.debug ?? false;
|
|
7060
|
-
}
|
|
7061
|
-
/**
|
|
7062
|
-
* Tracks an onboarding step view.
|
|
7063
|
-
* Saves the step name internally for implicit drop detection on the backend.
|
|
7064
|
-
*
|
|
7065
|
-
* @param stepName - Unique name for this onboarding step.
|
|
7066
|
-
*/
|
|
7067
|
-
async step(stepName) {
|
|
7068
|
-
this.assertConfig();
|
|
7069
|
-
this.validateStepName(stepName, "step");
|
|
7070
|
-
this.lastStep = stepName;
|
|
7071
|
-
const payload = {
|
|
7072
|
-
family: "onboarding",
|
|
7073
|
-
type: "step",
|
|
7074
|
-
...{ step_name: stepName }
|
|
7075
|
-
};
|
|
7076
|
-
return this.emit("onboarding", payload, "step");
|
|
7077
|
-
}
|
|
7078
|
-
/**
|
|
7079
|
-
* Tracks successful completion of the onboarding flow.
|
|
7080
|
-
* Marks the flow as finished.
|
|
7081
|
-
*/
|
|
7082
|
-
async complete() {
|
|
7083
|
-
this.assertConfig();
|
|
7084
|
-
this.finished = true;
|
|
7085
|
-
return this.emit("onboarding", { family: "onboarding", type: "complete" }, "complete");
|
|
7086
|
-
}
|
|
7087
|
-
/**
|
|
7088
|
-
* Tracks an explicit drop (abandonment) at the given step.
|
|
7089
|
-
* Marks the flow as finished.
|
|
7090
|
-
*
|
|
7091
|
-
* @param stepName - The step name where the user dropped off.
|
|
7092
|
-
*/
|
|
7093
|
-
async drop(stepName) {
|
|
7094
|
-
this.assertConfig();
|
|
7095
|
-
this.validateStepName(stepName, "drop");
|
|
7096
|
-
this.finished = true;
|
|
7097
|
-
const payload = {
|
|
7098
|
-
family: "onboarding",
|
|
7099
|
-
type: "drop",
|
|
7100
|
-
...{ step_name: stepName }
|
|
7101
|
-
};
|
|
7102
|
-
return this.emit("onboarding", payload, "drop");
|
|
7103
|
-
}
|
|
7104
|
-
/** Returns the last step name seen, or null if no step was tracked yet. */
|
|
7105
|
-
getLastStep() {
|
|
7106
|
-
return this.lastStep;
|
|
7107
|
-
}
|
|
7108
|
-
/** Returns whether the flow has been marked as finished (complete or drop). */
|
|
7109
|
-
isFinished() {
|
|
7110
|
-
return this.finished;
|
|
7111
|
-
}
|
|
7112
|
-
async emit(eventName, properties, logLabel) {
|
|
7113
|
-
const pipeline = this.pipeline;
|
|
7114
|
-
const distinctId = pipeline.getDistinctId();
|
|
7115
|
-
if (!distinctId) {
|
|
7116
|
-
if (this.debug) console.log(`[Paywallo:Onboarding] skipped (no distinctId): ${logLabel}`);
|
|
7117
|
-
return;
|
|
7472
|
+
const stale = this.cache.getStalePaywall(placement);
|
|
7473
|
+
return stale !== void 0 ? stale : null;
|
|
7118
7474
|
}
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7475
|
+
}
|
|
7476
|
+
async getEmergencyPaywall() {
|
|
7477
|
+
return getEmergencyPaywall(this);
|
|
7478
|
+
}
|
|
7479
|
+
async getCampaign(placement, distinctId, context) {
|
|
7480
|
+
const key = `${placement}:${distinctId}`;
|
|
7481
|
+
const hit = this.cache.getCampaign(key);
|
|
7482
|
+
if (hit !== void 0) return hit;
|
|
7483
|
+
try {
|
|
7484
|
+
const result = await getCampaignData(this, this.baseUrl, placement, distinctId, context);
|
|
7485
|
+
if (!result) {
|
|
7486
|
+
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
7487
|
+
return null;
|
|
7488
|
+
}
|
|
7489
|
+
this.cache.setCampaign(key, result);
|
|
7490
|
+
return result;
|
|
7491
|
+
} catch {
|
|
7492
|
+
const stale = this.cache.getStaleCampaign(key);
|
|
7493
|
+
return stale !== void 0 ? stale : null;
|
|
7122
7494
|
}
|
|
7123
7495
|
}
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7496
|
+
async getActivePlacements() {
|
|
7497
|
+
try {
|
|
7498
|
+
const res = await this.get("/sdk/campaigns/placements");
|
|
7499
|
+
if (!res.ok || !Array.isArray(res.data?.data)) return [];
|
|
7500
|
+
return res.data.data;
|
|
7501
|
+
} catch {
|
|
7502
|
+
return [];
|
|
7130
7503
|
}
|
|
7131
7504
|
}
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
);
|
|
7505
|
+
async getPrimaryCampaign(distinctId) {
|
|
7506
|
+
const key = `primary:${distinctId}`;
|
|
7507
|
+
const hit = this.cache.getCampaign(key);
|
|
7508
|
+
if (hit !== void 0) return hit;
|
|
7509
|
+
try {
|
|
7510
|
+
const res = await this.get(`/sdk/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
7511
|
+
if (res.status === 404) {
|
|
7512
|
+
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
7513
|
+
return null;
|
|
7514
|
+
}
|
|
7515
|
+
if (!res.ok) {
|
|
7516
|
+
const stale = this.cache.getStaleCampaign(key);
|
|
7517
|
+
return stale !== void 0 ? stale : null;
|
|
7518
|
+
}
|
|
7519
|
+
this.cache.setCampaign(key, res.data);
|
|
7520
|
+
return res.data;
|
|
7521
|
+
} catch {
|
|
7522
|
+
const stale = this.cache.getStaleCampaign(key);
|
|
7523
|
+
return stale !== void 0 ? stale : null;
|
|
7138
7524
|
}
|
|
7139
7525
|
}
|
|
7526
|
+
async validatePurchase(platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey) {
|
|
7527
|
+
return validatePurchase(this, this.appKey, platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey);
|
|
7528
|
+
}
|
|
7529
|
+
async getSubscriptionStatus(distinctId) {
|
|
7530
|
+
return getSubscriptionStatus(this, this.baseUrl, this.appKey, distinctId);
|
|
7531
|
+
}
|
|
7532
|
+
async evaluateFlags(keys, distinctId) {
|
|
7533
|
+
return evaluateFlags(this.flagDeps(), keys, distinctId);
|
|
7534
|
+
}
|
|
7535
|
+
async getConditionalFlag(flagKey, context) {
|
|
7536
|
+
return getConditionalFlag(this.flagDeps(), flagKey, context);
|
|
7537
|
+
}
|
|
7538
|
+
async getVariantFromCache(flagKey, distinctId) {
|
|
7539
|
+
return getVariantFromCache(this.flagDeps(), flagKey, distinctId);
|
|
7540
|
+
}
|
|
7541
|
+
flagDeps() {
|
|
7542
|
+
return {
|
|
7543
|
+
get: (path) => this.get(path),
|
|
7544
|
+
httpClient: this.httpClient,
|
|
7545
|
+
cache: this.cache,
|
|
7546
|
+
appKey: this.appKey,
|
|
7547
|
+
baseUrl: this.baseUrl
|
|
7548
|
+
};
|
|
7549
|
+
}
|
|
7140
7550
|
};
|
|
7141
|
-
onboardingManager = new OnboardingManager();
|
|
7142
|
-
}
|
|
7143
|
-
});
|
|
7144
|
-
|
|
7145
|
-
// src/domains/onboarding/index.ts
|
|
7146
|
-
var init_onboarding = __esm({
|
|
7147
|
-
"src/domains/onboarding/index.ts"() {
|
|
7148
|
-
"use strict";
|
|
7149
|
-
init_OnboardingManager();
|
|
7150
|
-
init_OnboardingError();
|
|
7151
|
-
}
|
|
7152
|
-
});
|
|
7153
|
-
|
|
7154
|
-
// src/domains/paywall/paywallHeartbeatRecovery.ts
|
|
7155
|
-
async function recoverPaywallHeartbeat(apiClient, distinctId, sessionId, debug) {
|
|
7156
|
-
const snapshot = await readPersistedHeartbeat();
|
|
7157
|
-
if (!snapshot) return false;
|
|
7158
|
-
try {
|
|
7159
|
-
const closedAt = new Date(snapshot.lastSeen);
|
|
7160
|
-
const durationS = Math.max(0, Math.round((snapshot.lastSeen - snapshot.presentedAt) / 1e3));
|
|
7161
|
-
await apiClient.trackEvent("paywall", distinctId, {
|
|
7162
|
-
type: "closed",
|
|
7163
|
-
paywall_id: snapshot.paywallId,
|
|
7164
|
-
placement: snapshot.placement,
|
|
7165
|
-
closed_at: closedAt.toISOString(),
|
|
7166
|
-
duration_s: durationS,
|
|
7167
|
-
close_reason: "error",
|
|
7168
|
-
...snapshot.variantId && { variant_id: snapshot.variantId },
|
|
7169
|
-
...snapshot.variantKey && { variant_key: snapshot.variantKey },
|
|
7170
|
-
...snapshot.campaignId && { campaign_id: snapshot.campaignId },
|
|
7171
|
-
...sessionId && { sessionId }
|
|
7172
|
-
});
|
|
7173
|
-
if (debug) console.log("[Paywallo HEARTBEAT] recovered orphan paywall close", {
|
|
7174
|
-
paywallId: snapshot.paywallId,
|
|
7175
|
-
durationS
|
|
7176
|
-
});
|
|
7177
|
-
return true;
|
|
7178
|
-
} catch (err) {
|
|
7179
|
-
if (debug) console.log("[Paywallo HEARTBEAT] recovery failed", err);
|
|
7180
|
-
return false;
|
|
7181
|
-
} finally {
|
|
7182
|
-
await clearPersistedHeartbeat();
|
|
7183
|
-
}
|
|
7184
|
-
}
|
|
7185
|
-
var init_paywallHeartbeatRecovery = __esm({
|
|
7186
|
-
"src/domains/paywall/paywallHeartbeatRecovery.ts"() {
|
|
7187
|
-
"use strict";
|
|
7188
|
-
init_paywallHeartbeat();
|
|
7189
7551
|
}
|
|
7190
7552
|
});
|
|
7191
7553
|
|
|
@@ -7229,6 +7591,8 @@ var init_eventPipelineBridge = __esm({
|
|
|
7229
7591
|
|
|
7230
7592
|
// src/core/PaywalloInitHelpers.ts
|
|
7231
7593
|
function setupNotifications(apiClient, config, environment, eventPipeline) {
|
|
7594
|
+
if (config.notifications === false) return;
|
|
7595
|
+
if (config.notifications === void 0 && !isNativePushAvailable()) return;
|
|
7232
7596
|
try {
|
|
7233
7597
|
notificationsManager.injectDeps({
|
|
7234
7598
|
httpClient: apiClient.getHttpClient(),
|
|
@@ -7270,6 +7634,10 @@ function setupAutoPreload(state, apiClient, config, distinctId) {
|
|
|
7270
7634
|
return null;
|
|
7271
7635
|
}).catch(() => null);
|
|
7272
7636
|
}
|
|
7637
|
+
function startBatchPreload(apiClient, debug) {
|
|
7638
|
+
void campaignGateService.preloadAllActive(apiClient, debug).catch(() => {
|
|
7639
|
+
});
|
|
7640
|
+
}
|
|
7273
7641
|
var init_PaywalloInitHelpers = __esm({
|
|
7274
7642
|
"src/core/PaywalloInitHelpers.ts"() {
|
|
7275
7643
|
"use strict";
|
|
@@ -7277,6 +7645,7 @@ var init_PaywalloInitHelpers = __esm({
|
|
|
7277
7645
|
init_identity();
|
|
7278
7646
|
init_notifications();
|
|
7279
7647
|
init_SecureStorage();
|
|
7648
|
+
init_NativePushBridge();
|
|
7280
7649
|
init_constants();
|
|
7281
7650
|
}
|
|
7282
7651
|
});
|
|
@@ -7390,6 +7759,7 @@ async function doInit(state, config) {
|
|
|
7390
7759
|
cacheTTL: config.subscriptionCacheTTL,
|
|
7391
7760
|
debug: config.debug
|
|
7392
7761
|
});
|
|
7762
|
+
planService.init({ apiClient, debug: config.debug ?? false });
|
|
7393
7763
|
await identityManager.initialize(apiClient, config.debug);
|
|
7394
7764
|
if (state.pendingIdentifies.length > 0) {
|
|
7395
7765
|
for (const pending of state.pendingIdentifies) {
|
|
@@ -7412,6 +7782,9 @@ async function doInit(state, config) {
|
|
|
7412
7782
|
} catch (err) {
|
|
7413
7783
|
if (config.debug) console.log("[Paywallo ATTR] start error", err);
|
|
7414
7784
|
}
|
|
7785
|
+
void nativeDeviceInfo.getDeviceInfo().catch(() => null);
|
|
7786
|
+
void advertisingIdManager.collect(false).catch(() => null);
|
|
7787
|
+
void metaBridge.getAnonymousID().catch(() => null);
|
|
7415
7788
|
apiClient.setEventContextProvider(() => {
|
|
7416
7789
|
const attr = attributionTracker.get();
|
|
7417
7790
|
const attrEntries = attr ? [
|
|
@@ -7426,11 +7799,35 @@ async function doInit(state, config) {
|
|
|
7426
7799
|
["referrer", attr.referrer]
|
|
7427
7800
|
].filter((pair) => pair[1] !== void 0 && pair[1] !== "") : [];
|
|
7428
7801
|
const attribution = attrEntries.length > 0 ? Object.fromEntries(attrEntries) : void 0;
|
|
7802
|
+
const adIds = advertisingIdManager.getCached();
|
|
7803
|
+
const fbAnonId = metaBridge.getCachedAnonymousID();
|
|
7804
|
+
const idsEntries = [
|
|
7805
|
+
["idfa", adIds?.idfa ?? null],
|
|
7806
|
+
["idfv", adIds?.idfv ?? null],
|
|
7807
|
+
["gaid", adIds?.gaid ?? null],
|
|
7808
|
+
["fb_anon_id", fbAnonId]
|
|
7809
|
+
].filter((pair) => pair[1] !== null && pair[1] !== "");
|
|
7810
|
+
const ids = idsEntries.length > 0 ? Object.fromEntries(idsEntries) : void 0;
|
|
7811
|
+
const device = nativeDeviceInfo.getCachedDeviceInfo();
|
|
7812
|
+
let locale;
|
|
7813
|
+
let timezone;
|
|
7814
|
+
try {
|
|
7815
|
+
const opts = Intl.DateTimeFormat().resolvedOptions();
|
|
7816
|
+
locale = opts.locale || void 0;
|
|
7817
|
+
timezone = opts.timeZone || void 0;
|
|
7818
|
+
} catch {
|
|
7819
|
+
}
|
|
7429
7820
|
return {
|
|
7430
7821
|
distinct_id: identityManager.getDistinctId() || void 0,
|
|
7431
7822
|
device_id: identityManager.getDeviceId() ?? void 0,
|
|
7432
7823
|
session_id: sessionManager.getSessionId() ?? void 0,
|
|
7433
|
-
|
|
7824
|
+
app_version: device?.appVersion && device.appVersion !== "0.0.0" ? device.appVersion : void 0,
|
|
7825
|
+
os_version: device?.systemVersion && device.systemVersion !== "0.0.0" ? device.systemVersion : void 0,
|
|
7826
|
+
device_model: device?.modelId || device?.model || void 0,
|
|
7827
|
+
timezone,
|
|
7828
|
+
locale,
|
|
7829
|
+
...attribution && Object.keys(attribution).length > 0 && { attribution },
|
|
7830
|
+
...ids && Object.keys(ids).length > 0 && { ids }
|
|
7434
7831
|
};
|
|
7435
7832
|
});
|
|
7436
7833
|
await sessionManager.initialize(
|
|
@@ -7464,7 +7861,7 @@ async function doInit(state, config) {
|
|
|
7464
7861
|
state.resolveReady();
|
|
7465
7862
|
state.resolveReady = null;
|
|
7466
7863
|
}
|
|
7467
|
-
|
|
7864
|
+
console.warn("[Paywallo] initialized successfully");
|
|
7468
7865
|
if (distinctId) {
|
|
7469
7866
|
apiClient.getSubscriptionStatus(distinctId).then(() => {
|
|
7470
7867
|
if (config.debug) console.log("[Paywallo SUB] preloaded on boot");
|
|
@@ -7475,26 +7872,30 @@ async function doInit(state, config) {
|
|
|
7475
7872
|
});
|
|
7476
7873
|
}
|
|
7477
7874
|
setupAutoPreload(state, apiClient, config, distinctId);
|
|
7875
|
+
startBatchPreload(apiClient, config.debug);
|
|
7478
7876
|
}
|
|
7479
7877
|
var init_PaywalloInitializer = __esm({
|
|
7480
7878
|
"src/core/PaywalloInitializer.ts"() {
|
|
7481
7879
|
"use strict";
|
|
7482
|
-
init_SubscriptionManager();
|
|
7483
|
-
init_ApiClient();
|
|
7484
7880
|
init_identity();
|
|
7881
|
+
init_plan();
|
|
7882
|
+
init_AdvertisingIdManager();
|
|
7485
7883
|
init_DeepLinkAttributionCapture();
|
|
7486
7884
|
init_InstallTracker();
|
|
7487
|
-
|
|
7488
|
-
init_queue();
|
|
7489
|
-
init_session();
|
|
7885
|
+
init_MetaBridge();
|
|
7490
7886
|
init_onboarding();
|
|
7491
|
-
init_NativeStorage();
|
|
7492
|
-
init_NativeDeviceInfo();
|
|
7493
7887
|
init_paywallHeartbeatRecovery();
|
|
7888
|
+
init_session();
|
|
7889
|
+
init_SubscriptionManager();
|
|
7890
|
+
init_NativeDeviceInfo();
|
|
7891
|
+
init_ApiClient();
|
|
7892
|
+
init_constants();
|
|
7494
7893
|
init_eventPipelineBridge();
|
|
7495
|
-
|
|
7894
|
+
init_network();
|
|
7496
7895
|
init_PaywalloInitHelpers();
|
|
7497
|
-
|
|
7896
|
+
init_PaywalloState();
|
|
7897
|
+
init_queue();
|
|
7898
|
+
init_NativeStorage();
|
|
7498
7899
|
}
|
|
7499
7900
|
});
|
|
7500
7901
|
|
|
@@ -7748,6 +8149,7 @@ var init_PaywalloClient = __esm({
|
|
|
7748
8149
|
init_PaywalloAnalytics();
|
|
7749
8150
|
init_PaywalloSubscription();
|
|
7750
8151
|
init_PaywalloFlags();
|
|
8152
|
+
init_plan();
|
|
7751
8153
|
PaywalloClientClass = class {
|
|
7752
8154
|
constructor() {
|
|
7753
8155
|
this.state = createPaywalloState();
|
|
@@ -7999,6 +8401,14 @@ var init_PaywalloClient = __esm({
|
|
|
7999
8401
|
async processOfflineQueue() {
|
|
8000
8402
|
return queueProcessor.processQueue();
|
|
8001
8403
|
}
|
|
8404
|
+
async getPlans() {
|
|
8405
|
+
this.ensureInitialized();
|
|
8406
|
+
return planService.getAllPlans();
|
|
8407
|
+
}
|
|
8408
|
+
async getCurrentPlan() {
|
|
8409
|
+
this.ensureInitialized();
|
|
8410
|
+
return planService.getCurrentPlan();
|
|
8411
|
+
}
|
|
8002
8412
|
getApiClientOrThrow() {
|
|
8003
8413
|
if (!this.state.config || !this.state.apiClient) throw new ClientError(CLIENT_ERROR_CODES.NOT_INITIALIZED, "SDK not initialized. Call Paywallo.init() first");
|
|
8004
8414
|
return this.state.apiClient;
|
|
@@ -8041,6 +8451,8 @@ __export(index_exports, {
|
|
|
8041
8451
|
PaywalloContext: () => PaywalloContext,
|
|
8042
8452
|
PaywalloError: () => PaywalloError,
|
|
8043
8453
|
PaywalloProvider: () => PaywalloProvider,
|
|
8454
|
+
PlanCache: () => PlanCache,
|
|
8455
|
+
PlanService: () => PlanService,
|
|
8044
8456
|
PurchaseError: () => PurchaseError,
|
|
8045
8457
|
SESSION_ERROR_CODES: () => SESSION_ERROR_CODES,
|
|
8046
8458
|
SessionError: () => SessionError,
|
|
@@ -8063,6 +8475,8 @@ __export(index_exports, {
|
|
|
8063
8475
|
offlineQueue: () => offlineQueue,
|
|
8064
8476
|
onboardingManager: () => onboardingManager,
|
|
8065
8477
|
parseVariables: () => parseVariables,
|
|
8478
|
+
planCache: () => planCache,
|
|
8479
|
+
planService: () => planService,
|
|
8066
8480
|
queueProcessor: () => queueProcessor,
|
|
8067
8481
|
resolveText: () => resolveText,
|
|
8068
8482
|
sessionManager: () => sessionManager,
|
|
@@ -8072,6 +8486,8 @@ __export(index_exports, {
|
|
|
8072
8486
|
useOnboarding: () => useOnboarding,
|
|
8073
8487
|
usePaywallContext: () => usePaywallContext,
|
|
8074
8488
|
usePaywallo: () => usePaywallo,
|
|
8489
|
+
usePlanPurchase: () => usePlanPurchase,
|
|
8490
|
+
usePlans: () => usePlans,
|
|
8075
8491
|
useProducts: () => useProducts,
|
|
8076
8492
|
usePurchase: () => usePurchase,
|
|
8077
8493
|
useSubscription: () => useSubscription
|
|
@@ -8146,8 +8562,124 @@ function usePaywallo() {
|
|
|
8146
8562
|
return context;
|
|
8147
8563
|
}
|
|
8148
8564
|
|
|
8149
|
-
// src/hooks/
|
|
8565
|
+
// src/hooks/usePlans.ts
|
|
8150
8566
|
var import_react13 = require("react");
|
|
8567
|
+
async function getPlanService() {
|
|
8568
|
+
try {
|
|
8569
|
+
const mod = await Promise.resolve().then(() => (init_PlanService(), PlanService_exports));
|
|
8570
|
+
return mod.planService ?? null;
|
|
8571
|
+
} catch {
|
|
8572
|
+
return null;
|
|
8573
|
+
}
|
|
8574
|
+
}
|
|
8575
|
+
function usePlans() {
|
|
8576
|
+
const [allPlans, setAllPlans] = (0, import_react13.useState)([]);
|
|
8577
|
+
const [currentPlan, setCurrentPlan] = (0, import_react13.useState)(null);
|
|
8578
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
8579
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
8580
|
+
const fetchPlans = (0, import_react13.useCallback)(async (forceRefresh = false) => {
|
|
8581
|
+
setIsLoading(true);
|
|
8582
|
+
setError(null);
|
|
8583
|
+
try {
|
|
8584
|
+
const service = await getPlanService();
|
|
8585
|
+
if (!service) {
|
|
8586
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, "PlanService not available");
|
|
8587
|
+
}
|
|
8588
|
+
const response = await service.getAllPlans(forceRefresh);
|
|
8589
|
+
const { plans, currentIdentifier } = response;
|
|
8590
|
+
setAllPlans(plans);
|
|
8591
|
+
setCurrentPlan(
|
|
8592
|
+
currentIdentifier != null ? plans.find((p) => p.identifier === currentIdentifier) ?? null : null
|
|
8593
|
+
);
|
|
8594
|
+
} catch (err) {
|
|
8595
|
+
const e = err instanceof PurchaseError ? err : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, String(err));
|
|
8596
|
+
setError(e);
|
|
8597
|
+
} finally {
|
|
8598
|
+
setIsLoading(false);
|
|
8599
|
+
}
|
|
8600
|
+
}, []);
|
|
8601
|
+
const refresh = (0, import_react13.useCallback)(() => {
|
|
8602
|
+
return fetchPlans(true);
|
|
8603
|
+
}, [fetchPlans]);
|
|
8604
|
+
(0, import_react13.useEffect)(() => {
|
|
8605
|
+
void fetchPlans(false);
|
|
8606
|
+
}, [fetchPlans]);
|
|
8607
|
+
return { currentPlan, allPlans, isLoading, error, refresh };
|
|
8608
|
+
}
|
|
8609
|
+
|
|
8610
|
+
// src/hooks/usePlanPurchase.ts
|
|
8611
|
+
var import_react14 = require("react");
|
|
8612
|
+
async function invalidatePlanCache() {
|
|
8613
|
+
try {
|
|
8614
|
+
const mod = await Promise.resolve().then(() => (init_PlanService(), PlanService_exports));
|
|
8615
|
+
mod.planService?.invalidateCache();
|
|
8616
|
+
} catch {
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
function usePlanPurchase() {
|
|
8620
|
+
const [state, setState] = (0, import_react14.useState)("idle");
|
|
8621
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
8622
|
+
const purchase = (0, import_react14.useCallback)(async (productId) => {
|
|
8623
|
+
setState("purchasing");
|
|
8624
|
+
setError(null);
|
|
8625
|
+
try {
|
|
8626
|
+
const iapService = getIAPService();
|
|
8627
|
+
const result = await iapService.purchase(productId);
|
|
8628
|
+
setState("idle");
|
|
8629
|
+
if (result.success) {
|
|
8630
|
+
await invalidatePlanCache();
|
|
8631
|
+
}
|
|
8632
|
+
return result.success ? {
|
|
8633
|
+
success: true,
|
|
8634
|
+
purchase: result.purchase ? {
|
|
8635
|
+
productId: result.purchase.productId,
|
|
8636
|
+
transactionId: result.purchase.transactionId ?? "",
|
|
8637
|
+
transactionDate: result.purchase.transactionDate,
|
|
8638
|
+
receipt: result.purchase.receipt,
|
|
8639
|
+
platform: "ios"
|
|
8640
|
+
} : void 0
|
|
8641
|
+
} : { success: false, error: result.error };
|
|
8642
|
+
} catch (err) {
|
|
8643
|
+
const purchaseError = err instanceof PurchaseError ? err : createPurchaseError("PURCHASE_FAILED", err instanceof Error ? err.message : String(err));
|
|
8644
|
+
if (purchaseError.userCancelled) {
|
|
8645
|
+
setState("idle");
|
|
8646
|
+
return null;
|
|
8647
|
+
}
|
|
8648
|
+
setError(purchaseError);
|
|
8649
|
+
setState("error");
|
|
8650
|
+
return { success: false, error: purchaseError };
|
|
8651
|
+
}
|
|
8652
|
+
}, []);
|
|
8653
|
+
const restore = (0, import_react14.useCallback)(async () => {
|
|
8654
|
+
setState("restoring");
|
|
8655
|
+
setError(null);
|
|
8656
|
+
try {
|
|
8657
|
+
const iapService = getIAPService();
|
|
8658
|
+
const transactions = await iapService.restore();
|
|
8659
|
+
setState("idle");
|
|
8660
|
+
await invalidatePlanCache();
|
|
8661
|
+
return {
|
|
8662
|
+
restoredCount: transactions.length,
|
|
8663
|
+
productIds: transactions.map((tx) => tx.productId)
|
|
8664
|
+
};
|
|
8665
|
+
} catch (err) {
|
|
8666
|
+
const e = err instanceof PurchaseError ? err : createPurchaseError("RESTORE_FAILED", String(err));
|
|
8667
|
+
setError(e);
|
|
8668
|
+
setState("error");
|
|
8669
|
+
return null;
|
|
8670
|
+
}
|
|
8671
|
+
}, []);
|
|
8672
|
+
return {
|
|
8673
|
+
purchase,
|
|
8674
|
+
restore,
|
|
8675
|
+
isPurchasing: state === "purchasing",
|
|
8676
|
+
isRestoring: state === "restoring",
|
|
8677
|
+
error
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8680
|
+
|
|
8681
|
+
// src/hooks/useProducts.ts
|
|
8682
|
+
var import_react15 = require("react");
|
|
8151
8683
|
|
|
8152
8684
|
// src/utils/productMappers.ts
|
|
8153
8685
|
function mapToIAPProduct(product) {
|
|
@@ -8186,11 +8718,11 @@ function mapToFormattedProduct(product) {
|
|
|
8186
8718
|
|
|
8187
8719
|
// src/hooks/useProducts.ts
|
|
8188
8720
|
function useProducts(initialProductIds) {
|
|
8189
|
-
const [products, setProducts] = (0,
|
|
8190
|
-
const [formattedProducts, setFormattedProducts] = (0,
|
|
8191
|
-
const [isLoading, setIsLoading] = (0,
|
|
8192
|
-
const [error, setError] = (0,
|
|
8193
|
-
const loadProducts = (0,
|
|
8721
|
+
const [products, setProducts] = (0, import_react15.useState)([]);
|
|
8722
|
+
const [formattedProducts, setFormattedProducts] = (0, import_react15.useState)([]);
|
|
8723
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
|
|
8724
|
+
const [error, setError] = (0, import_react15.useState)(null);
|
|
8725
|
+
const loadProducts = (0, import_react15.useCallback)(async (productIds) => {
|
|
8194
8726
|
setIsLoading(true);
|
|
8195
8727
|
setError(null);
|
|
8196
8728
|
try {
|
|
@@ -8204,24 +8736,24 @@ function useProducts(initialProductIds) {
|
|
|
8204
8736
|
setIsLoading(false);
|
|
8205
8737
|
}
|
|
8206
8738
|
}, []);
|
|
8207
|
-
(0,
|
|
8739
|
+
(0, import_react15.useEffect)(() => {
|
|
8208
8740
|
if (initialProductIds && initialProductIds.length > 0) {
|
|
8209
8741
|
void loadProducts(initialProductIds);
|
|
8210
8742
|
}
|
|
8211
8743
|
}, []);
|
|
8212
|
-
const getProduct = (0,
|
|
8744
|
+
const getProduct = (0, import_react15.useCallback)(
|
|
8213
8745
|
(productId) => {
|
|
8214
8746
|
return products.find((p) => p.productId === productId);
|
|
8215
8747
|
},
|
|
8216
8748
|
[products]
|
|
8217
8749
|
);
|
|
8218
|
-
const getFormattedProduct = (0,
|
|
8750
|
+
const getFormattedProduct = (0, import_react15.useCallback)(
|
|
8219
8751
|
(productId) => {
|
|
8220
8752
|
return formattedProducts.find((p) => p.productId === productId);
|
|
8221
8753
|
},
|
|
8222
8754
|
[formattedProducts]
|
|
8223
8755
|
);
|
|
8224
|
-
const getPriceInfo = (0,
|
|
8756
|
+
const getPriceInfo = (0, import_react15.useCallback)(
|
|
8225
8757
|
(productId) => {
|
|
8226
8758
|
const p = formattedProducts.find((fp) => fp.productId === productId);
|
|
8227
8759
|
if (!p) return void 0;
|
|
@@ -8250,11 +8782,11 @@ function useProducts(initialProductIds) {
|
|
|
8250
8782
|
}
|
|
8251
8783
|
|
|
8252
8784
|
// src/hooks/usePurchase.ts
|
|
8253
|
-
var
|
|
8785
|
+
var import_react16 = require("react");
|
|
8254
8786
|
function usePurchase() {
|
|
8255
|
-
const [state, setState] = (0,
|
|
8256
|
-
const [error, setError] = (0,
|
|
8257
|
-
const purchase = (0,
|
|
8787
|
+
const [state, setState] = (0, import_react16.useState)("idle");
|
|
8788
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
8789
|
+
const purchase = (0, import_react16.useCallback)(async (productId) => {
|
|
8258
8790
|
setState("purchasing");
|
|
8259
8791
|
setError(null);
|
|
8260
8792
|
try {
|
|
@@ -8290,7 +8822,7 @@ function usePurchase() {
|
|
|
8290
8822
|
return { status: "failed", error: purchaseError };
|
|
8291
8823
|
}
|
|
8292
8824
|
}, []);
|
|
8293
|
-
const restore = (0,
|
|
8825
|
+
const restore = (0, import_react16.useCallback)(async () => {
|
|
8294
8826
|
setState("restoring");
|
|
8295
8827
|
setError(null);
|
|
8296
8828
|
try {
|
|
@@ -8321,14 +8853,14 @@ function usePurchase() {
|
|
|
8321
8853
|
}
|
|
8322
8854
|
|
|
8323
8855
|
// src/hooks/useSubscription.ts
|
|
8324
|
-
var
|
|
8856
|
+
var import_react17 = require("react");
|
|
8325
8857
|
init_SubscriptionManager();
|
|
8326
8858
|
var EMPTY_ENTITLEMENTS = [];
|
|
8327
8859
|
function useSubscription() {
|
|
8328
|
-
const [status, setStatus] = (0,
|
|
8329
|
-
const [isLoading, setIsLoading] = (0,
|
|
8330
|
-
const [error, setError] = (0,
|
|
8331
|
-
const refresh = (0,
|
|
8860
|
+
const [status, setStatus] = (0, import_react17.useState)(null);
|
|
8861
|
+
const [isLoading, setIsLoading] = (0, import_react17.useState)(true);
|
|
8862
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
8863
|
+
const refresh = (0, import_react17.useCallback)(async () => {
|
|
8332
8864
|
setIsLoading(true);
|
|
8333
8865
|
setError(null);
|
|
8334
8866
|
try {
|
|
@@ -8341,7 +8873,7 @@ function useSubscription() {
|
|
|
8341
8873
|
setIsLoading(false);
|
|
8342
8874
|
}
|
|
8343
8875
|
}, []);
|
|
8344
|
-
const restore = (0,
|
|
8876
|
+
const restore = (0, import_react17.useCallback)(async () => {
|
|
8345
8877
|
setIsLoading(true);
|
|
8346
8878
|
setError(null);
|
|
8347
8879
|
try {
|
|
@@ -8354,7 +8886,7 @@ function useSubscription() {
|
|
|
8354
8886
|
setIsLoading(false);
|
|
8355
8887
|
}
|
|
8356
8888
|
}, []);
|
|
8357
|
-
(0,
|
|
8889
|
+
(0, import_react17.useEffect)(() => {
|
|
8358
8890
|
void subscriptionManager.getSubscriptionStatus().then((s) => {
|
|
8359
8891
|
setStatus(s);
|
|
8360
8892
|
setIsLoading(false);
|
|
@@ -8381,8 +8913,11 @@ function useSubscription() {
|
|
|
8381
8913
|
};
|
|
8382
8914
|
}
|
|
8383
8915
|
|
|
8916
|
+
// src/index.ts
|
|
8917
|
+
init_plan();
|
|
8918
|
+
|
|
8384
8919
|
// src/PaywalloProvider.tsx
|
|
8385
|
-
var
|
|
8920
|
+
var import_react23 = require("react");
|
|
8386
8921
|
var import_react_native24 = require("react-native");
|
|
8387
8922
|
init_paywall();
|
|
8388
8923
|
init_paywall();
|
|
@@ -8390,7 +8925,7 @@ init_paywall();
|
|
|
8390
8925
|
init_PaywalloClient();
|
|
8391
8926
|
|
|
8392
8927
|
// src/hooks/useAppAutoEvents.ts
|
|
8393
|
-
var
|
|
8928
|
+
var import_react18 = require("react");
|
|
8394
8929
|
var FIRST_SEEN_KEY = "@panel:firstSeen";
|
|
8395
8930
|
var DEBOUNCE_MS = 1e3;
|
|
8396
8931
|
async function detectPlatform3() {
|
|
@@ -8420,8 +8955,8 @@ function useAppAutoEvents(config) {
|
|
|
8420
8955
|
storageSet,
|
|
8421
8956
|
debug
|
|
8422
8957
|
} = config;
|
|
8423
|
-
const didRunRef = (0,
|
|
8424
|
-
(0,
|
|
8958
|
+
const didRunRef = (0, import_react18.useRef)(false);
|
|
8959
|
+
(0, import_react18.useEffect)(() => {
|
|
8425
8960
|
if (!isInitialized || didRunRef.current) return;
|
|
8426
8961
|
const timer = setTimeout(() => {
|
|
8427
8962
|
if (didRunRef.current) return;
|
|
@@ -8466,7 +9001,7 @@ function useAppAutoEvents(config) {
|
|
|
8466
9001
|
}
|
|
8467
9002
|
|
|
8468
9003
|
// src/hooks/useCampaignPreload.ts
|
|
8469
|
-
var
|
|
9004
|
+
var import_react19 = require("react");
|
|
8470
9005
|
init_PaywalloClient();
|
|
8471
9006
|
init_CampaignError();
|
|
8472
9007
|
|
|
@@ -8537,17 +9072,17 @@ function getCacheEntry(cache, placement) {
|
|
|
8537
9072
|
|
|
8538
9073
|
// src/hooks/useCampaignPreload.ts
|
|
8539
9074
|
function useCampaignPreload() {
|
|
8540
|
-
const [preloadedWebView, setPreloadedWebView] = (0,
|
|
8541
|
-
const preloadedCampaignsRef = (0,
|
|
8542
|
-
const isPreloadValid = (0,
|
|
9075
|
+
const [preloadedWebView, setPreloadedWebView] = (0, import_react19.useState)(null);
|
|
9076
|
+
const preloadedCampaignsRef = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
|
|
9077
|
+
const isPreloadValid = (0, import_react19.useCallback)(
|
|
8543
9078
|
(placement) => isCacheEntryValid(preloadedCampaignsRef.current.get(placement)),
|
|
8544
9079
|
[]
|
|
8545
9080
|
);
|
|
8546
|
-
const consumePreloadedCampaign = (0,
|
|
9081
|
+
const consumePreloadedCampaign = (0, import_react19.useCallback)(
|
|
8547
9082
|
(placement) => getCacheEntry(preloadedCampaignsRef.current, placement),
|
|
8548
9083
|
[]
|
|
8549
9084
|
);
|
|
8550
|
-
const preloadCampaign = (0,
|
|
9085
|
+
const preloadCampaign = (0, import_react19.useCallback)(
|
|
8551
9086
|
async (placement, context) => {
|
|
8552
9087
|
try {
|
|
8553
9088
|
const campaign = await PaywalloClient.getCampaign(placement, context);
|
|
@@ -8621,12 +9156,12 @@ init_SecureStorage();
|
|
|
8621
9156
|
init_paywall();
|
|
8622
9157
|
|
|
8623
9158
|
// src/hooks/useProductLoader.ts
|
|
8624
|
-
var
|
|
9159
|
+
var import_react20 = require("react");
|
|
8625
9160
|
init_PaywalloClient();
|
|
8626
9161
|
function useProductLoader() {
|
|
8627
|
-
const [products, setProducts] = (0,
|
|
8628
|
-
const [isLoadingProducts, setIsLoadingProducts] = (0,
|
|
8629
|
-
const refreshProducts = (0,
|
|
9162
|
+
const [products, setProducts] = (0, import_react20.useState)(/* @__PURE__ */ new Map());
|
|
9163
|
+
const [isLoadingProducts, setIsLoadingProducts] = (0, import_react20.useState)(false);
|
|
9164
|
+
const refreshProducts = (0, import_react20.useCallback)(async (productIds) => {
|
|
8630
9165
|
setIsLoadingProducts(true);
|
|
8631
9166
|
try {
|
|
8632
9167
|
const iapService = getIAPService();
|
|
@@ -8644,12 +9179,12 @@ function useProductLoader() {
|
|
|
8644
9179
|
}
|
|
8645
9180
|
|
|
8646
9181
|
// src/hooks/usePurchaseOrchestrator.ts
|
|
8647
|
-
var
|
|
9182
|
+
var import_react21 = require("react");
|
|
8648
9183
|
init_PaywalloClient();
|
|
8649
9184
|
init_paywall();
|
|
8650
9185
|
function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, invalidateSubscriptionCache) {
|
|
8651
9186
|
const { trackDismissed, trackProductSelected, trackPurchased } = usePaywallTracking();
|
|
8652
|
-
const handlePreloadedPurchase = (0,
|
|
9187
|
+
const handlePreloadedPurchase = (0, import_react21.useCallback)(
|
|
8653
9188
|
async (productId) => {
|
|
8654
9189
|
try {
|
|
8655
9190
|
if (preloadedWebView) {
|
|
@@ -8687,7 +9222,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
8687
9222
|
},
|
|
8688
9223
|
[preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, trackDismissed, trackProductSelected, trackPurchased, invalidateSubscriptionCache]
|
|
8689
9224
|
);
|
|
8690
|
-
const handlePreloadedRestore = (0,
|
|
9225
|
+
const handlePreloadedRestore = (0, import_react21.useCallback)(async () => {
|
|
8691
9226
|
try {
|
|
8692
9227
|
const transactions = await getIAPService().restore();
|
|
8693
9228
|
if (transactions.length === 0) return;
|
|
@@ -8710,7 +9245,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
8710
9245
|
}
|
|
8711
9246
|
|
|
8712
9247
|
// src/hooks/useSubscriptionSync.ts
|
|
8713
|
-
var
|
|
9248
|
+
var import_react22 = require("react");
|
|
8714
9249
|
init_PaywalloClient();
|
|
8715
9250
|
init_SubscriptionCache();
|
|
8716
9251
|
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
@@ -8777,14 +9312,14 @@ function isActiveCacheEntry(entry) {
|
|
|
8777
9312
|
return isSubscriptionStillActive(entry.data);
|
|
8778
9313
|
}
|
|
8779
9314
|
function useSubscriptionSync() {
|
|
8780
|
-
const [subscription, setSubscription] = (0,
|
|
8781
|
-
const cacheRef = (0,
|
|
8782
|
-
const invalidateCache = (0,
|
|
9315
|
+
const [subscription, setSubscription] = (0, import_react22.useState)(null);
|
|
9316
|
+
const cacheRef = (0, import_react22.useRef)(null);
|
|
9317
|
+
const invalidateCache = (0, import_react22.useCallback)(() => {
|
|
8783
9318
|
cacheRef.current = null;
|
|
8784
9319
|
const distinctId = PaywalloClient.getDistinctId();
|
|
8785
9320
|
if (distinctId) void subscriptionCache.invalidate(distinctId);
|
|
8786
9321
|
}, []);
|
|
8787
|
-
const fetchAndCache = (0,
|
|
9322
|
+
const fetchAndCache = (0, import_react22.useCallback)(async () => {
|
|
8788
9323
|
const apiClient = PaywalloClient.getApiClient();
|
|
8789
9324
|
const distinctId = PaywalloClient.getDistinctId();
|
|
8790
9325
|
if (!apiClient || !distinctId) return null;
|
|
@@ -8798,7 +9333,7 @@ function useSubscriptionSync() {
|
|
|
8798
9333
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
8799
9334
|
return sub;
|
|
8800
9335
|
}, []);
|
|
8801
|
-
const hasActiveSubscription = (0,
|
|
9336
|
+
const hasActiveSubscription = (0, import_react22.useCallback)(async () => {
|
|
8802
9337
|
const apiClient = PaywalloClient.getApiClient();
|
|
8803
9338
|
const distinctId = PaywalloClient.getDistinctId();
|
|
8804
9339
|
if (!apiClient || !distinctId) return false;
|
|
@@ -8841,7 +9376,7 @@ function useSubscriptionSync() {
|
|
|
8841
9376
|
return resolveOfflineFromCache(distinctId);
|
|
8842
9377
|
}
|
|
8843
9378
|
}, []);
|
|
8844
|
-
const getSubscription = (0,
|
|
9379
|
+
const getSubscription = (0, import_react22.useCallback)(async () => {
|
|
8845
9380
|
const apiClient = PaywalloClient.getApiClient();
|
|
8846
9381
|
const distinctId = PaywalloClient.getDistinctId();
|
|
8847
9382
|
if (!apiClient || !distinctId) return null;
|
|
@@ -8868,20 +9403,20 @@ init_ClientError();
|
|
|
8868
9403
|
init_localization();
|
|
8869
9404
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
8870
9405
|
function PaywalloProvider({ children, config }) {
|
|
8871
|
-
const [isInitialized, setIsInitialized] = (0,
|
|
8872
|
-
const [initError, setInitError] = (0,
|
|
8873
|
-
const [distinctId, setDistinctId] = (0,
|
|
8874
|
-
const [activePaywall, setActivePaywall] = (0,
|
|
9406
|
+
const [isInitialized, setIsInitialized] = (0, import_react23.useState)(false);
|
|
9407
|
+
const [initError, setInitError] = (0, import_react23.useState)(null);
|
|
9408
|
+
const [distinctId, setDistinctId] = (0, import_react23.useState)(null);
|
|
9409
|
+
const [activePaywall, setActivePaywall] = (0, import_react23.useState)(null);
|
|
8875
9410
|
const { products, isLoadingProducts, refreshProducts } = useProductLoader();
|
|
8876
9411
|
const { subscription, hasActiveSubscription, getSubscription, invalidateCache } = useSubscriptionSync();
|
|
8877
9412
|
const { preloadedWebView, setPreloadedWebView, preloadCampaign, consumePreloadedCampaign, isPreloadValid } = useCampaignPreload();
|
|
8878
|
-
const clearPreloadedWebView = (0,
|
|
8879
|
-
const autoPreloadTriggeredRef = (0,
|
|
8880
|
-
const preloadedWebViewRef = (0,
|
|
8881
|
-
const pollTimerRef = (0,
|
|
8882
|
-
const pollCancelledRef = (0,
|
|
8883
|
-
const secureStorageRef = (0,
|
|
8884
|
-
(0,
|
|
9413
|
+
const clearPreloadedWebView = (0, import_react23.useCallback)(() => setPreloadedWebView(null), [setPreloadedWebView]);
|
|
9414
|
+
const autoPreloadTriggeredRef = (0, import_react23.useRef)(false);
|
|
9415
|
+
const preloadedWebViewRef = (0, import_react23.useRef)(preloadedWebView);
|
|
9416
|
+
const pollTimerRef = (0, import_react23.useRef)(null);
|
|
9417
|
+
const pollCancelledRef = (0, import_react23.useRef)(false);
|
|
9418
|
+
const secureStorageRef = (0, import_react23.useRef)(new SecureStorage(config.debug));
|
|
9419
|
+
(0, import_react23.useEffect)(() => {
|
|
8885
9420
|
preloadedWebViewRef.current = preloadedWebView;
|
|
8886
9421
|
}, [preloadedWebView]);
|
|
8887
9422
|
useAppAutoEvents({
|
|
@@ -8897,20 +9432,20 @@ function PaywalloProvider({ children, config }) {
|
|
|
8897
9432
|
storageSet: (key, value) => secureStorageRef.current.set(key, value),
|
|
8898
9433
|
debug: config.debug
|
|
8899
9434
|
});
|
|
8900
|
-
const triggerRepreload = (0,
|
|
9435
|
+
const triggerRepreload = (0, import_react23.useCallback)((placement) => {
|
|
8901
9436
|
void PaywalloClient.preloadCampaign(placement).catch(() => {
|
|
8902
9437
|
});
|
|
8903
9438
|
}, []);
|
|
8904
9439
|
const { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady: baseHandlePreloadedWebViewReady, handlePreloadedClose: baseHandlePreloadedClose, setShowingPreloadedWebView, presentedAtRef } = usePaywallPresenter(preloadedWebView, setPreloadedWebView);
|
|
8905
|
-
const SCREEN_HEIGHT = (0,
|
|
8906
|
-
const slideAnim = (0,
|
|
8907
|
-
const handlePreloadedWebViewReady = (0,
|
|
9440
|
+
const SCREEN_HEIGHT = (0, import_react23.useMemo)(() => import_react_native24.Dimensions.get("window").height, []);
|
|
9441
|
+
const slideAnim = (0, import_react23.useRef)(new import_react_native24.Animated.Value(SCREEN_HEIGHT)).current;
|
|
9442
|
+
const handlePreloadedWebViewReady = (0, import_react23.useCallback)(() => {
|
|
8908
9443
|
if (PaywalloClient.getConfig()?.debug) {
|
|
8909
9444
|
console.log(`[Paywallo WEBVIEW] loaded \u2014 placement: ${preloadedWebView?.placement}`);
|
|
8910
9445
|
}
|
|
8911
9446
|
baseHandlePreloadedWebViewReady();
|
|
8912
9447
|
}, [preloadedWebView?.placement, baseHandlePreloadedWebViewReady]);
|
|
8913
|
-
const handlePreloadedClose = (0,
|
|
9448
|
+
const handlePreloadedClose = (0, import_react23.useCallback)(() => {
|
|
8914
9449
|
const placement = preloadedWebView?.placement;
|
|
8915
9450
|
import_react_native24.Animated.timing(slideAnim, { toValue: SCREEN_HEIGHT, duration: 200, easing: import_react_native24.Easing.in(import_react_native24.Easing.cubic), useNativeDriver: true }).start(() => {
|
|
8916
9451
|
baseHandlePreloadedClose();
|
|
@@ -8925,8 +9460,8 @@ function PaywalloProvider({ children, config }) {
|
|
|
8925
9460
|
presentedAtRef,
|
|
8926
9461
|
invalidateCache
|
|
8927
9462
|
);
|
|
8928
|
-
const [isPreloadPurchasing, setIsPreloadPurchasing] = (0,
|
|
8929
|
-
const handlePreloadedPurchase = (0,
|
|
9463
|
+
const [isPreloadPurchasing, setIsPreloadPurchasing] = (0, import_react23.useState)(false);
|
|
9464
|
+
const handlePreloadedPurchase = (0, import_react23.useCallback)(async (productId) => {
|
|
8930
9465
|
setIsPreloadPurchasing(true);
|
|
8931
9466
|
try {
|
|
8932
9467
|
await rawPreloadedPurchase(productId);
|
|
@@ -8934,8 +9469,8 @@ function PaywalloProvider({ children, config }) {
|
|
|
8934
9469
|
setIsPreloadPurchasing(false);
|
|
8935
9470
|
}
|
|
8936
9471
|
}, [rawPreloadedPurchase]);
|
|
8937
|
-
const configRef = (0,
|
|
8938
|
-
(0,
|
|
9472
|
+
const configRef = (0, import_react23.useRef)(config);
|
|
9473
|
+
(0, import_react23.useEffect)(() => {
|
|
8939
9474
|
let mounted = true;
|
|
8940
9475
|
initLocalization({ detectDevice: true });
|
|
8941
9476
|
PaywalloClient.init(configRef.current).then(async () => {
|
|
@@ -8956,14 +9491,14 @@ function PaywalloProvider({ children, config }) {
|
|
|
8956
9491
|
mounted = false;
|
|
8957
9492
|
};
|
|
8958
9493
|
}, [preloadCampaign]);
|
|
8959
|
-
const getPaywallConfig = (0,
|
|
9494
|
+
const getPaywallConfig = (0, import_react23.useCallback)(async (p) => {
|
|
8960
9495
|
const api = PaywalloClient.getApiClient();
|
|
8961
9496
|
return api ? api.getPaywall(p) : null;
|
|
8962
9497
|
}, []);
|
|
8963
|
-
const presentPaywall = (0,
|
|
9498
|
+
const presentPaywall = (0, import_react23.useCallback)((placement) => {
|
|
8964
9499
|
return new Promise((resolve) => setActivePaywall({ placement, resolver: resolve }));
|
|
8965
9500
|
}, []);
|
|
8966
|
-
const trackCampaignImpression = (0,
|
|
9501
|
+
const trackCampaignImpression = (0, import_react23.useCallback)((placement, variantKey, campaignId) => {
|
|
8967
9502
|
const api = PaywalloClient.getApiClient();
|
|
8968
9503
|
if (!api) return;
|
|
8969
9504
|
const sessionId = PaywalloClient.getSessionId();
|
|
@@ -8977,7 +9512,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
8977
9512
|
}).catch(() => {
|
|
8978
9513
|
});
|
|
8979
9514
|
}, []);
|
|
8980
|
-
const presentCampaign = (0,
|
|
9515
|
+
const presentCampaign = (0, import_react23.useCallback)(
|
|
8981
9516
|
async (placement, context) => {
|
|
8982
9517
|
try {
|
|
8983
9518
|
if (preloadedWebView?.placement === placement && preloadedWebView.loaded && isPreloadValid(placement)) {
|
|
@@ -9051,7 +9586,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9051
9586
|
},
|
|
9052
9587
|
[preloadedWebView, isPreloadValid, consumePreloadedCampaign, presentPreloadedWebView, trackCampaignImpression]
|
|
9053
9588
|
);
|
|
9054
|
-
const restorePurchases = (0,
|
|
9589
|
+
const restorePurchases = (0, import_react23.useCallback)(async () => {
|
|
9055
9590
|
invalidateCache();
|
|
9056
9591
|
try {
|
|
9057
9592
|
const txs = await getIAPService().restore();
|
|
@@ -9060,13 +9595,13 @@ function PaywalloProvider({ children, config }) {
|
|
|
9060
9595
|
return { success: false, restoredProducts: [], error: error instanceof Error ? error : new PurchaseError(PURCHASE_ERROR_CODES.RESTORE_FAILED, String(error)) };
|
|
9061
9596
|
}
|
|
9062
9597
|
}, [invalidateCache]);
|
|
9063
|
-
const handlePaywallResult = (0,
|
|
9598
|
+
const handlePaywallResult = (0, import_react23.useCallback)((result) => {
|
|
9064
9599
|
if (activePaywall) {
|
|
9065
9600
|
activePaywall.resolver(result);
|
|
9066
9601
|
setActivePaywall(null);
|
|
9067
9602
|
}
|
|
9068
9603
|
}, [activePaywall]);
|
|
9069
|
-
const bridgePaywallPresenter = (0,
|
|
9604
|
+
const bridgePaywallPresenter = (0, import_react23.useCallback)((placement) => {
|
|
9070
9605
|
if (PaywalloClient.getConfig()?.debug) {
|
|
9071
9606
|
console.log(`[Paywallo PRESENT] called \u2014 preloaded: ${preloadedWebViewRef.current?.loaded === true} placement: ${placement}`);
|
|
9072
9607
|
}
|
|
@@ -9095,7 +9630,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9095
9630
|
}
|
|
9096
9631
|
return presentCampaign(placement);
|
|
9097
9632
|
}, [presentPreloadedWebView, presentCampaign]);
|
|
9098
|
-
(0,
|
|
9633
|
+
(0, import_react23.useEffect)(() => {
|
|
9099
9634
|
if (!isInitialized) return;
|
|
9100
9635
|
const onEmergency = async (id) => {
|
|
9101
9636
|
try {
|
|
@@ -9122,9 +9657,9 @@ function PaywalloProvider({ children, config }) {
|
|
|
9122
9657
|
};
|
|
9123
9658
|
}, [isInitialized, bridgePaywallPresenter, getSubscription, hasActiveSubscription, restorePurchases]);
|
|
9124
9659
|
const isReady = isInitialized && !isLoadingProducts;
|
|
9125
|
-
const noOp = (0,
|
|
9660
|
+
const noOp = (0, import_react23.useCallback)(() => {
|
|
9126
9661
|
}, []);
|
|
9127
|
-
const contextValue = (0,
|
|
9662
|
+
const contextValue = (0, import_react23.useMemo)(() => ({
|
|
9128
9663
|
config: PaywalloClient.getConfig(),
|
|
9129
9664
|
isInitialized,
|
|
9130
9665
|
isReady,
|
|
@@ -9158,7 +9693,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9158
9693
|
getPaywallConfig,
|
|
9159
9694
|
refreshProducts
|
|
9160
9695
|
]);
|
|
9161
|
-
(0,
|
|
9696
|
+
(0, import_react23.useLayoutEffect)(() => {
|
|
9162
9697
|
if (showingPreloadedWebView) {
|
|
9163
9698
|
slideAnim.setValue(SCREEN_HEIGHT);
|
|
9164
9699
|
import_react_native24.Animated.timing(slideAnim, { toValue: 0, duration: 200, easing: import_react_native24.Easing.out(import_react_native24.Easing.cubic), useNativeDriver: true }).start();
|
|
@@ -9365,6 +9900,8 @@ var index_default = Paywallo;
|
|
|
9365
9900
|
PaywalloContext,
|
|
9366
9901
|
PaywalloError,
|
|
9367
9902
|
PaywalloProvider,
|
|
9903
|
+
PlanCache,
|
|
9904
|
+
PlanService,
|
|
9368
9905
|
PurchaseError,
|
|
9369
9906
|
SESSION_ERROR_CODES,
|
|
9370
9907
|
SessionError,
|
|
@@ -9386,6 +9923,8 @@ var index_default = Paywallo;
|
|
|
9386
9923
|
offlineQueue,
|
|
9387
9924
|
onboardingManager,
|
|
9388
9925
|
parseVariables,
|
|
9926
|
+
planCache,
|
|
9927
|
+
planService,
|
|
9389
9928
|
queueProcessor,
|
|
9390
9929
|
resolveText,
|
|
9391
9930
|
sessionManager,
|
|
@@ -9395,6 +9934,8 @@ var index_default = Paywallo;
|
|
|
9395
9934
|
useOnboarding,
|
|
9396
9935
|
usePaywallContext,
|
|
9397
9936
|
usePaywallo,
|
|
9937
|
+
usePlanPurchase,
|
|
9938
|
+
usePlans,
|
|
9398
9939
|
useProducts,
|
|
9399
9940
|
usePurchase,
|
|
9400
9941
|
useSubscription
|