@virex-tech/paywallo-sdk 2.2.5 → 2.2.7
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/android/src/main/java/com/paywallo/sdk/PaywalloEnvModule.kt +31 -0
- package/android/src/main/java/com/paywallo/sdk/PaywalloSdkPackage.kt +2 -1
- package/dist/index.d.mts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +1340 -682
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1251 -594
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloEnv.m +8 -0
- package/ios/PaywalloEnv.swift +28 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -830,9 +830,9 @@ var init_CampaignGateService = __esm({
|
|
|
830
830
|
}
|
|
831
831
|
}
|
|
832
832
|
getPreloadedCampaign(placement) {
|
|
833
|
-
const
|
|
834
|
-
if (!
|
|
835
|
-
const age = Date.now() -
|
|
833
|
+
const cached2 = this.preloadedCampaigns.get(placement);
|
|
834
|
+
if (!cached2) return null;
|
|
835
|
+
const age = Date.now() - cached2.preloadedAt;
|
|
836
836
|
if (age >= PRELOAD_CACHE_TTL_MS) {
|
|
837
837
|
this.preloadedCampaigns.delete(placement);
|
|
838
838
|
return null;
|
|
@@ -841,7 +841,7 @@ var init_CampaignGateService = __esm({
|
|
|
841
841
|
void this.preloadCampaign(this.apiClientRef, placement).catch(() => {
|
|
842
842
|
});
|
|
843
843
|
}
|
|
844
|
-
return
|
|
844
|
+
return cached2.campaign;
|
|
845
845
|
}
|
|
846
846
|
async preloadAllActive(apiClient, debug) {
|
|
847
847
|
this.apiClientRef = apiClient;
|
|
@@ -2173,7 +2173,7 @@ function extractPayload(data) {
|
|
|
2173
2173
|
}
|
|
2174
2174
|
function setupForegroundHandler(deps, onReceive) {
|
|
2175
2175
|
const { bridge, tracker, debug } = deps;
|
|
2176
|
-
const
|
|
2176
|
+
const unsubscribe2 = bridge.onMessage(async (message) => {
|
|
2177
2177
|
const data = message.data ?? {};
|
|
2178
2178
|
const payload = extractPayload({
|
|
2179
2179
|
...data,
|
|
@@ -2191,7 +2191,7 @@ function setupForegroundHandler(deps, onReceive) {
|
|
|
2191
2191
|
messageId
|
|
2192
2192
|
});
|
|
2193
2193
|
});
|
|
2194
|
-
return
|
|
2194
|
+
return unsubscribe2;
|
|
2195
2195
|
}
|
|
2196
2196
|
var init_ForegroundHandler = __esm({
|
|
2197
2197
|
"src/domains/notifications/handlers/ForegroundHandler.ts"() {
|
|
@@ -2386,8 +2386,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2386
2386
|
// src/core/version.ts
|
|
2387
2387
|
function resolveVersion() {
|
|
2388
2388
|
try {
|
|
2389
|
-
if ("2.2.
|
|
2390
|
-
return "2.2.
|
|
2389
|
+
if ("2.2.7") {
|
|
2390
|
+
return "2.2.7";
|
|
2391
2391
|
}
|
|
2392
2392
|
} catch {
|
|
2393
2393
|
}
|
|
@@ -2459,9 +2459,6 @@ function mapPermissionStatus(status) {
|
|
|
2459
2459
|
function detectPlatform2() {
|
|
2460
2460
|
return import_react_native11.Platform.OS === "ios" ? "ios" : "android";
|
|
2461
2461
|
}
|
|
2462
|
-
function detectEnvironment() {
|
|
2463
|
-
return typeof __DEV__ !== "undefined" && __DEV__ ? "sandbox" : "production";
|
|
2464
|
-
}
|
|
2465
2462
|
async function getAppVersion() {
|
|
2466
2463
|
try {
|
|
2467
2464
|
const { collectDeviceInfo: collectDeviceInfo2 } = await Promise.resolve().then(() => (init_deviceInfo(), deviceInfo_exports));
|
|
@@ -2502,7 +2499,7 @@ async function clearPersistedToken(secureStorage2) {
|
|
|
2502
2499
|
} catch {
|
|
2503
2500
|
}
|
|
2504
2501
|
}
|
|
2505
|
-
async function buildRegistration(token, getDeviceId, getDistinctId) {
|
|
2502
|
+
async function buildRegistration(token, getDeviceId, getDistinctId, environment) {
|
|
2506
2503
|
const appVersion = await getAppVersion();
|
|
2507
2504
|
return {
|
|
2508
2505
|
token,
|
|
@@ -2513,7 +2510,7 @@ async function buildRegistration(token, getDeviceId, getDistinctId) {
|
|
|
2513
2510
|
deviceId: getDeviceId?.() ?? void 0,
|
|
2514
2511
|
locale: await getLocale(),
|
|
2515
2512
|
timezone: getTimezone2(),
|
|
2516
|
-
environment
|
|
2513
|
+
environment
|
|
2517
2514
|
};
|
|
2518
2515
|
}
|
|
2519
2516
|
async function registerToken(deps, token) {
|
|
@@ -2522,7 +2519,8 @@ async function registerToken(deps, token) {
|
|
|
2522
2519
|
if (debug) console.log("[Paywallo PUSH] httpClient not ready, skipping token registration");
|
|
2523
2520
|
return;
|
|
2524
2521
|
}
|
|
2525
|
-
const
|
|
2522
|
+
const { environment } = deps;
|
|
2523
|
+
const registration = await buildRegistration(token, getDeviceId, getDistinctId, environment);
|
|
2526
2524
|
try {
|
|
2527
2525
|
await httpClient.post(
|
|
2528
2526
|
TOKEN_ENDPOINT,
|
|
@@ -2572,7 +2570,8 @@ async function registerAndPersistToken(deps, token) {
|
|
|
2572
2570
|
appKey: deps.appKey,
|
|
2573
2571
|
getDeviceId: deps.getDeviceId,
|
|
2574
2572
|
getDistinctId: deps.getDistinctId,
|
|
2575
|
-
debug: deps.debug
|
|
2573
|
+
debug: deps.debug,
|
|
2574
|
+
environment: deps.environment
|
|
2576
2575
|
},
|
|
2577
2576
|
token
|
|
2578
2577
|
);
|
|
@@ -2589,7 +2588,8 @@ function subscribeTokenRefresh(bridge, deps, onToken) {
|
|
|
2589
2588
|
appKey: deps.appKey,
|
|
2590
2589
|
getDeviceId: deps.getDeviceId,
|
|
2591
2590
|
getDistinctId: deps.getDistinctId,
|
|
2592
|
-
debug: deps.debug
|
|
2591
|
+
debug: deps.debug,
|
|
2592
|
+
environment: deps.environment
|
|
2593
2593
|
},
|
|
2594
2594
|
newToken
|
|
2595
2595
|
).catch(() => void 0);
|
|
@@ -2797,6 +2797,7 @@ var init_NotificationsManager = __esm({
|
|
|
2797
2797
|
this.getDistinctId = null;
|
|
2798
2798
|
this.appKey = null;
|
|
2799
2799
|
this.apiBaseUrl = null;
|
|
2800
|
+
this.environment = "production";
|
|
2800
2801
|
this.tokenRefreshCleanup = null;
|
|
2801
2802
|
this.foregroundCleanup = null;
|
|
2802
2803
|
this.pendingHandlersConfig = null;
|
|
@@ -2816,6 +2817,7 @@ var init_NotificationsManager = __esm({
|
|
|
2816
2817
|
this.secureStorage = deps.secureStorage;
|
|
2817
2818
|
this.getDeviceId = deps.getDeviceId;
|
|
2818
2819
|
if (deps.getDistinctId) this.getDistinctId = deps.getDistinctId;
|
|
2820
|
+
if (deps.environment) this.environment = deps.environment;
|
|
2819
2821
|
}
|
|
2820
2822
|
async initialize(config) {
|
|
2821
2823
|
this.applyConfig(config);
|
|
@@ -2858,7 +2860,8 @@ var init_NotificationsManager = __esm({
|
|
|
2858
2860
|
appKey: this.appKey,
|
|
2859
2861
|
getDeviceId: this.getDeviceId,
|
|
2860
2862
|
getDistinctId: this.getDistinctId,
|
|
2861
|
-
debug: this.debug
|
|
2863
|
+
debug: this.debug,
|
|
2864
|
+
environment: this.environment
|
|
2862
2865
|
};
|
|
2863
2866
|
}
|
|
2864
2867
|
async doRegisterToken(token) {
|
|
@@ -3054,6 +3057,41 @@ var init_emitPaywallClosed = __esm({
|
|
|
3054
3057
|
}
|
|
3055
3058
|
});
|
|
3056
3059
|
|
|
3060
|
+
// src/domains/paywall/extractFirstPageBackground.ts
|
|
3061
|
+
function extractFirstPageBackground(craftData) {
|
|
3062
|
+
if (!craftData) return DEFAULT_BACKGROUND;
|
|
3063
|
+
try {
|
|
3064
|
+
const data = JSON.parse(craftData);
|
|
3065
|
+
const nodes = { ...data.nodes, ...data.sharedNodes };
|
|
3066
|
+
const rootId = data.rootId;
|
|
3067
|
+
if (!rootId || !nodes[rootId]) return DEFAULT_BACKGROUND;
|
|
3068
|
+
const firstPageId = nodes[rootId].children?.[0];
|
|
3069
|
+
if (!firstPageId) return DEFAULT_BACKGROUND;
|
|
3070
|
+
const bg = nodes[firstPageId]?.props?.backgroundColor;
|
|
3071
|
+
return typeof bg === "string" && bg.length > 0 && bg !== "transparent" ? bg : DEFAULT_BACKGROUND;
|
|
3072
|
+
} catch {
|
|
3073
|
+
return DEFAULT_BACKGROUND;
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
function isColorDark(color) {
|
|
3077
|
+
const hex = color.replace("#", "").trim();
|
|
3078
|
+
const normalized = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
3079
|
+
if (normalized.length !== 6) return false;
|
|
3080
|
+
const r = parseInt(normalized.slice(0, 2), 16);
|
|
3081
|
+
const g = parseInt(normalized.slice(2, 4), 16);
|
|
3082
|
+
const b = parseInt(normalized.slice(4, 6), 16);
|
|
3083
|
+
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return false;
|
|
3084
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
3085
|
+
return luminance < 0.5;
|
|
3086
|
+
}
|
|
3087
|
+
var DEFAULT_BACKGROUND;
|
|
3088
|
+
var init_extractFirstPageBackground = __esm({
|
|
3089
|
+
"src/domains/paywall/extractFirstPageBackground.ts"() {
|
|
3090
|
+
"use strict";
|
|
3091
|
+
DEFAULT_BACKGROUND = "#FFFFFF";
|
|
3092
|
+
}
|
|
3093
|
+
});
|
|
3094
|
+
|
|
3057
3095
|
// src/domains/paywall/parseWebViewMessage.ts
|
|
3058
3096
|
function deriveMessageId(message) {
|
|
3059
3097
|
if (message.id) return message.id;
|
|
@@ -3296,6 +3334,66 @@ var init_localization = __esm({
|
|
|
3296
3334
|
}
|
|
3297
3335
|
});
|
|
3298
3336
|
|
|
3337
|
+
// src/domains/paywall/PaywallSkeleton.tsx
|
|
3338
|
+
function SkeletonBlock({ style, color, opacity }) {
|
|
3339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native14.Animated.View, { style: [style, { backgroundColor: color, opacity }] });
|
|
3340
|
+
}
|
|
3341
|
+
function PaywallSkeleton({ backgroundColor = "#FFFFFF" }) {
|
|
3342
|
+
const pulse = (0, import_react3.useRef)(new import_react_native14.Animated.Value(0.4)).current;
|
|
3343
|
+
(0, import_react3.useEffect)(() => {
|
|
3344
|
+
const loop = import_react_native14.Animated.loop(
|
|
3345
|
+
import_react_native14.Animated.sequence([
|
|
3346
|
+
import_react_native14.Animated.timing(pulse, { toValue: 1, duration: 700, useNativeDriver: true }),
|
|
3347
|
+
import_react_native14.Animated.timing(pulse, { toValue: 0.4, duration: 700, useNativeDriver: true })
|
|
3348
|
+
])
|
|
3349
|
+
);
|
|
3350
|
+
loop.start();
|
|
3351
|
+
return () => loop.stop();
|
|
3352
|
+
}, [pulse]);
|
|
3353
|
+
const placeholder = isColorDark(backgroundColor) ? "rgba(255,255,255,0.13)" : "rgba(0,0,0,0.07)";
|
|
3354
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native14.View, { style: [styles.container, { backgroundColor }], pointerEvents: "none", children: [
|
|
3355
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native14.View, { style: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.logo, color: placeholder, opacity: pulse }) }),
|
|
3356
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.hero, color: placeholder, opacity: pulse }),
|
|
3357
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native14.View, { style: styles.titleGroup, children: [
|
|
3358
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.titleLine, color: placeholder, opacity: pulse }),
|
|
3359
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.titleLineShort, color: placeholder, opacity: pulse })
|
|
3360
|
+
] }),
|
|
3361
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native14.View, { style: styles.cardsRow, children: [
|
|
3362
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.card, color: placeholder, opacity: pulse }),
|
|
3363
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.card, color: placeholder, opacity: pulse })
|
|
3364
|
+
] }),
|
|
3365
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native14.View, { style: styles.footerGroup, children: [
|
|
3366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.cta, color: placeholder, opacity: pulse }),
|
|
3367
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonBlock, { style: styles.footer, color: placeholder, opacity: pulse })
|
|
3368
|
+
] })
|
|
3369
|
+
] });
|
|
3370
|
+
}
|
|
3371
|
+
var import_react3, import_react_native14, import_jsx_runtime, RADIUS, styles;
|
|
3372
|
+
var init_PaywallSkeleton = __esm({
|
|
3373
|
+
"src/domains/paywall/PaywallSkeleton.tsx"() {
|
|
3374
|
+
"use strict";
|
|
3375
|
+
import_react3 = require("react");
|
|
3376
|
+
import_react_native14 = require("react-native");
|
|
3377
|
+
init_extractFirstPageBackground();
|
|
3378
|
+
import_jsx_runtime = require("react/jsx-runtime");
|
|
3379
|
+
RADIUS = 14;
|
|
3380
|
+
styles = import_react_native14.StyleSheet.create({
|
|
3381
|
+
card: { borderRadius: RADIUS, flex: 1, height: 120 },
|
|
3382
|
+
cardsRow: { flexDirection: "row", gap: 12, marginTop: "auto", paddingHorizontal: 24 },
|
|
3383
|
+
container: { flex: 1, paddingBottom: 40, paddingTop: 64 },
|
|
3384
|
+
cta: { borderRadius: 30, height: 58, marginHorizontal: 24 },
|
|
3385
|
+
footer: { alignSelf: "center", borderRadius: 6, height: 12, marginTop: 20, width: 180 },
|
|
3386
|
+
footerGroup: { marginTop: 28 },
|
|
3387
|
+
header: { alignItems: "center", paddingVertical: 12 },
|
|
3388
|
+
hero: { alignSelf: "center", borderRadius: 20, height: 220, marginTop: 16, width: "70%" },
|
|
3389
|
+
logo: { borderRadius: 6, height: 22, width: 110 },
|
|
3390
|
+
titleGroup: { alignItems: "center", gap: 12, marginTop: 28, paddingHorizontal: 24 },
|
|
3391
|
+
titleLine: { borderRadius: 8, height: 26, width: "85%" },
|
|
3392
|
+
titleLineShort: { borderRadius: 8, height: 26, width: "60%" }
|
|
3393
|
+
});
|
|
3394
|
+
}
|
|
3395
|
+
});
|
|
3396
|
+
|
|
3299
3397
|
// src/domains/paywall/paywallScripts.ts
|
|
3300
3398
|
function buildPaywallInjectionScript(data) {
|
|
3301
3399
|
const paywallData = {
|
|
@@ -3344,7 +3442,7 @@ function getNativeWebView() {
|
|
|
3344
3442
|
if (NativeWebViewComponent) return NativeWebViewComponent;
|
|
3345
3443
|
if (nativeWebViewLookupFailed) return null;
|
|
3346
3444
|
try {
|
|
3347
|
-
NativeWebViewComponent = (0,
|
|
3445
|
+
NativeWebViewComponent = (0, import_react_native15.requireNativeComponent)("PaywalloWebView");
|
|
3348
3446
|
return NativeWebViewComponent;
|
|
3349
3447
|
} catch {
|
|
3350
3448
|
nativeWebViewLookupFailed = true;
|
|
@@ -3353,9 +3451,9 @@ function getNativeWebView() {
|
|
|
3353
3451
|
}
|
|
3354
3452
|
function getWebViewEmitter() {
|
|
3355
3453
|
if (webViewEmitter) return webViewEmitter;
|
|
3356
|
-
const mod =
|
|
3454
|
+
const mod = import_react_native15.NativeModules.PaywalloWebViewModule;
|
|
3357
3455
|
if (!mod) return null;
|
|
3358
|
-
webViewEmitter = new
|
|
3456
|
+
webViewEmitter = new import_react_native15.NativeEventEmitter(mod);
|
|
3359
3457
|
return webViewEmitter;
|
|
3360
3458
|
}
|
|
3361
3459
|
async function triggerNativeHaptic(style) {
|
|
@@ -3397,16 +3495,16 @@ function PaywallWebView({
|
|
|
3397
3495
|
onReady,
|
|
3398
3496
|
onError
|
|
3399
3497
|
}) {
|
|
3400
|
-
const paywallDataSent = (0,
|
|
3401
|
-
const loadEndReceived = (0,
|
|
3402
|
-
const [scriptToInject, setScriptToInject] = (0,
|
|
3403
|
-
const webViewRef = (0,
|
|
3404
|
-
const onErrorRef = (0,
|
|
3498
|
+
const paywallDataSent = (0, import_react4.useRef)(false);
|
|
3499
|
+
const loadEndReceived = (0, import_react4.useRef)(false);
|
|
3500
|
+
const [scriptToInject, setScriptToInject] = (0, import_react4.useState)(void 0);
|
|
3501
|
+
const webViewRef = (0, import_react4.useRef)(null);
|
|
3502
|
+
const onErrorRef = (0, import_react4.useRef)(onError);
|
|
3405
3503
|
onErrorRef.current = onError;
|
|
3406
|
-
const onReadyRef = (0,
|
|
3504
|
+
const onReadyRef = (0, import_react4.useRef)(onReady);
|
|
3407
3505
|
onReadyRef.current = onReady;
|
|
3408
|
-
const NativeWebView = (0,
|
|
3409
|
-
(0,
|
|
3506
|
+
const NativeWebView = (0, import_react4.useMemo)(() => getNativeWebView(), []);
|
|
3507
|
+
(0, import_react4.useEffect)(() => {
|
|
3410
3508
|
if (!NativeWebView) {
|
|
3411
3509
|
onErrorRef.current?.({
|
|
3412
3510
|
code: -1,
|
|
@@ -3414,10 +3512,10 @@ function PaywallWebView({
|
|
|
3414
3512
|
});
|
|
3415
3513
|
}
|
|
3416
3514
|
}, [NativeWebView]);
|
|
3417
|
-
const [resolvedWebUrl, setResolvedWebUrl] = (0,
|
|
3515
|
+
const [resolvedWebUrl, setResolvedWebUrl] = (0, import_react4.useState)(
|
|
3418
3516
|
() => webUrlProp ?? PaywalloClient.getWebUrl()
|
|
3419
3517
|
);
|
|
3420
|
-
(0,
|
|
3518
|
+
(0, import_react4.useEffect)(() => {
|
|
3421
3519
|
if (webUrlProp !== void 0) {
|
|
3422
3520
|
setResolvedWebUrl(webUrlProp ?? null);
|
|
3423
3521
|
return;
|
|
@@ -3436,7 +3534,7 @@ function PaywallWebView({
|
|
|
3436
3534
|
}, 200);
|
|
3437
3535
|
return () => clearInterval(interval);
|
|
3438
3536
|
}, [webUrlProp]);
|
|
3439
|
-
(0,
|
|
3537
|
+
(0, import_react4.useEffect)(() => {
|
|
3440
3538
|
if (!resolvedWebUrl) {
|
|
3441
3539
|
onErrorRef.current?.({
|
|
3442
3540
|
code: -1,
|
|
@@ -3444,16 +3542,16 @@ function PaywallWebView({
|
|
|
3444
3542
|
});
|
|
3445
3543
|
}
|
|
3446
3544
|
}, []);
|
|
3447
|
-
const injectScript = (0,
|
|
3448
|
-
if (
|
|
3449
|
-
const handle = (0,
|
|
3545
|
+
const injectScript = (0, import_react4.useCallback)((script) => {
|
|
3546
|
+
if (import_react_native15.Platform.OS === "android") {
|
|
3547
|
+
const handle = (0, import_react_native15.findNodeHandle)(webViewRef.current);
|
|
3450
3548
|
if (handle == null) return;
|
|
3451
|
-
|
|
3549
|
+
import_react_native15.UIManager.dispatchViewManagerCommand(handle, "injectJavaScript", [script]);
|
|
3452
3550
|
return;
|
|
3453
3551
|
}
|
|
3454
3552
|
setScriptToInject(script);
|
|
3455
3553
|
}, []);
|
|
3456
|
-
const buildAndSetInjectionScript = (0,
|
|
3554
|
+
const buildAndSetInjectionScript = (0, import_react4.useCallback)(() => {
|
|
3457
3555
|
if (!craftData || paywallDataSent.current) return;
|
|
3458
3556
|
paywallDataSent.current = true;
|
|
3459
3557
|
const script = buildPaywallInjectionScript({
|
|
@@ -3464,16 +3562,16 @@ function PaywallWebView({
|
|
|
3464
3562
|
});
|
|
3465
3563
|
injectScript(script);
|
|
3466
3564
|
}, [craftData, products, primaryProductId, secondaryProductId, injectScript]);
|
|
3467
|
-
const processedIdsRef = (0,
|
|
3468
|
-
const dedupeTimersRef = (0,
|
|
3469
|
-
(0,
|
|
3565
|
+
const processedIdsRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
|
|
3566
|
+
const dedupeTimersRef = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
|
|
3567
|
+
(0, import_react4.useEffect)(() => {
|
|
3470
3568
|
return () => {
|
|
3471
3569
|
for (const timerId of dedupeTimersRef.current.values()) clearTimeout(timerId);
|
|
3472
3570
|
dedupeTimersRef.current.clear();
|
|
3473
3571
|
processedIdsRef.current.clear();
|
|
3474
3572
|
};
|
|
3475
3573
|
}, []);
|
|
3476
|
-
const handleParsedMessage = (0,
|
|
3574
|
+
const handleParsedMessage = (0, import_react4.useCallback)(
|
|
3477
3575
|
(message) => {
|
|
3478
3576
|
const msgId = deriveMessageId(message);
|
|
3479
3577
|
if (processedIdsRef.current.has(msgId)) return;
|
|
@@ -3507,7 +3605,7 @@ function PaywallWebView({
|
|
|
3507
3605
|
if (message.payload?.url) {
|
|
3508
3606
|
const url = message.payload.url;
|
|
3509
3607
|
if (/^https?:\/\//i.test(url) || /^mailto:/i.test(url) || /^itms-apps:/i.test(url) || /^market:/i.test(url)) {
|
|
3510
|
-
void
|
|
3608
|
+
void import_react_native15.Linking.openURL(url);
|
|
3511
3609
|
}
|
|
3512
3610
|
}
|
|
3513
3611
|
break;
|
|
@@ -3518,7 +3616,7 @@ function PaywallWebView({
|
|
|
3518
3616
|
},
|
|
3519
3617
|
[buildAndSetInjectionScript, onPurchase, onClose, onRestore]
|
|
3520
3618
|
);
|
|
3521
|
-
(0,
|
|
3619
|
+
(0, import_react4.useEffect)(() => {
|
|
3522
3620
|
const emitter = getWebViewEmitter();
|
|
3523
3621
|
if (!emitter) return;
|
|
3524
3622
|
const loadEndSub = emitter.addListener("PaywalloWebViewLoadEnd", () => {
|
|
@@ -3543,7 +3641,7 @@ function PaywallWebView({
|
|
|
3543
3641
|
errorSub.remove();
|
|
3544
3642
|
};
|
|
3545
3643
|
}, [buildAndSetInjectionScript, handleParsedMessage]);
|
|
3546
|
-
(0,
|
|
3644
|
+
(0, import_react4.useEffect)(() => {
|
|
3547
3645
|
const timer = setTimeout(() => {
|
|
3548
3646
|
if (!paywallDataSent.current) {
|
|
3549
3647
|
onErrorRef.current?.({
|
|
@@ -3554,13 +3652,13 @@ function PaywallWebView({
|
|
|
3554
3652
|
}, 1e4);
|
|
3555
3653
|
return () => clearTimeout(timer);
|
|
3556
3654
|
}, []);
|
|
3557
|
-
const handleLoadEnd = (0,
|
|
3655
|
+
const handleLoadEnd = (0, import_react4.useCallback)(() => {
|
|
3558
3656
|
if (!loadEndReceived.current) {
|
|
3559
3657
|
loadEndReceived.current = true;
|
|
3560
3658
|
buildAndSetInjectionScript();
|
|
3561
3659
|
}
|
|
3562
3660
|
}, [buildAndSetInjectionScript]);
|
|
3563
|
-
const handleNativeError = (0,
|
|
3661
|
+
const handleNativeError = (0, import_react4.useCallback)((event) => {
|
|
3564
3662
|
const ne = event.nativeEvent;
|
|
3565
3663
|
let errorData;
|
|
3566
3664
|
if (ne["payload"] && typeof ne["payload"] === "object") {
|
|
@@ -3576,30 +3674,30 @@ function PaywallWebView({
|
|
|
3576
3674
|
}
|
|
3577
3675
|
onErrorRef.current?.(parseErrorEvent(errorData));
|
|
3578
3676
|
}, []);
|
|
3579
|
-
const handleMessage = (0,
|
|
3677
|
+
const handleMessage = (0, import_react4.useCallback)(
|
|
3580
3678
|
(event) => {
|
|
3581
3679
|
const message = parseWebViewMessage(event.nativeEvent.data);
|
|
3582
3680
|
if (message) handleParsedMessage(message);
|
|
3583
3681
|
},
|
|
3584
3682
|
[handleParsedMessage]
|
|
3585
3683
|
);
|
|
3586
|
-
(0,
|
|
3684
|
+
(0, import_react4.useEffect)(() => {
|
|
3587
3685
|
if (!paywallDataSent.current) return;
|
|
3588
3686
|
injectScript(buildPurchaseStateScript(isPurchasing));
|
|
3589
3687
|
}, [isPurchasing, injectScript]);
|
|
3590
|
-
(0,
|
|
3591
|
-
if (
|
|
3688
|
+
(0, import_react4.useEffect)(() => {
|
|
3689
|
+
if (import_react_native15.Platform.OS !== "android") return;
|
|
3592
3690
|
const onBackPress = () => {
|
|
3593
3691
|
if (!paywallDataSent.current) return false;
|
|
3594
3692
|
injectScript(buildBackButtonScript());
|
|
3595
3693
|
return true;
|
|
3596
3694
|
};
|
|
3597
|
-
const subscription =
|
|
3695
|
+
const subscription = import_react_native15.BackHandler.addEventListener("hardwareBackPress", onBackPress);
|
|
3598
3696
|
return () => subscription.remove();
|
|
3599
3697
|
}, [injectScript]);
|
|
3600
3698
|
if (!resolvedWebUrl || !NativeWebView) return null;
|
|
3601
3699
|
const paywallUrl = `${resolvedWebUrl}/paywall/${paywallId}`;
|
|
3602
|
-
return /* @__PURE__ */ (0,
|
|
3700
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native15.View, { style: styles2.container, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
3603
3701
|
NativeWebView,
|
|
3604
3702
|
{
|
|
3605
3703
|
ref: webViewRef,
|
|
@@ -3608,24 +3706,24 @@ function PaywallWebView({
|
|
|
3608
3706
|
onMessage: handleMessage,
|
|
3609
3707
|
onLoadEnd: handleLoadEnd,
|
|
3610
3708
|
onError: handleNativeError,
|
|
3611
|
-
style:
|
|
3709
|
+
style: styles2.webview
|
|
3612
3710
|
}
|
|
3613
3711
|
) });
|
|
3614
3712
|
}
|
|
3615
|
-
var
|
|
3713
|
+
var import_react4, import_react_native15, import_jsx_runtime2, NativeWebViewComponent, nativeWebViewLookupFailed, webViewEmitter, styles2;
|
|
3616
3714
|
var init_PaywallWebView = __esm({
|
|
3617
3715
|
"src/domains/paywall/PaywallWebView.tsx"() {
|
|
3618
3716
|
"use strict";
|
|
3619
|
-
|
|
3620
|
-
|
|
3717
|
+
import_react4 = require("react");
|
|
3718
|
+
import_react_native15 = require("react-native");
|
|
3621
3719
|
init_PaywalloClient();
|
|
3622
3720
|
init_parseWebViewMessage();
|
|
3623
3721
|
init_paywallScripts();
|
|
3624
|
-
|
|
3722
|
+
import_jsx_runtime2 = require("react/jsx-runtime");
|
|
3625
3723
|
NativeWebViewComponent = null;
|
|
3626
3724
|
nativeWebViewLookupFailed = false;
|
|
3627
3725
|
webViewEmitter = null;
|
|
3628
|
-
|
|
3726
|
+
styles2 = import_react_native15.StyleSheet.create({
|
|
3629
3727
|
container: { flex: 1 },
|
|
3630
3728
|
webview: { flex: 1, backgroundColor: "transparent" }
|
|
3631
3729
|
});
|
|
@@ -3760,7 +3858,7 @@ function mapNativePurchase(native) {
|
|
|
3760
3858
|
transactionId: native.transactionId,
|
|
3761
3859
|
transactionDate: native.transactionDate,
|
|
3762
3860
|
receipt: native.receipt,
|
|
3763
|
-
platform:
|
|
3861
|
+
platform: import_react_native16.Platform.OS
|
|
3764
3862
|
};
|
|
3765
3863
|
}
|
|
3766
3864
|
function normalizeTransactionUpdate(raw) {
|
|
@@ -3780,17 +3878,17 @@ function normalizeTransactionUpdate(raw) {
|
|
|
3780
3878
|
if (typeof r.currency === "string") update.currency = r.currency;
|
|
3781
3879
|
return update;
|
|
3782
3880
|
}
|
|
3783
|
-
var
|
|
3881
|
+
var import_react_native16, TRANSACTION_UPDATE_EVENT, PaywalloStoreKitNative, nativeStoreKit, NativeStoreKit;
|
|
3784
3882
|
var init_NativeStoreKit = __esm({
|
|
3785
3883
|
"src/domains/iap/NativeStoreKit.ts"() {
|
|
3786
3884
|
"use strict";
|
|
3787
|
-
|
|
3885
|
+
import_react_native16 = require("react-native");
|
|
3788
3886
|
init_PaywalloClient();
|
|
3789
3887
|
init_uuid();
|
|
3790
3888
|
init_IdentityManager();
|
|
3791
3889
|
init_PurchaseError();
|
|
3792
3890
|
TRANSACTION_UPDATE_EVENT = "PaywalloTransactionUpdate";
|
|
3793
|
-
PaywalloStoreKitNative =
|
|
3891
|
+
PaywalloStoreKitNative = import_react_native16.NativeModules.PaywalloStoreKit ?? null;
|
|
3794
3892
|
nativeStoreKit = {
|
|
3795
3893
|
isAvailable: isAvailable3,
|
|
3796
3894
|
async getProducts(productIds) {
|
|
@@ -3859,7 +3957,7 @@ var init_NativeStoreKit = __esm({
|
|
|
3859
3957
|
subscribeToTransactionUpdates(listener) {
|
|
3860
3958
|
if (!PaywalloStoreKitNative) return null;
|
|
3861
3959
|
try {
|
|
3862
|
-
const EmitterCtor =
|
|
3960
|
+
const EmitterCtor = import_react_native16.NativeEventEmitter;
|
|
3863
3961
|
const emitter = new EmitterCtor(PaywalloStoreKitNative);
|
|
3864
3962
|
const sub = emitter.addListener(TRANSACTION_UPDATE_EVENT, (payload) => {
|
|
3865
3963
|
const update = normalizeTransactionUpdate(payload);
|
|
@@ -3919,6 +4017,32 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
3919
4017
|
if (this.getDebug()) console.log("[Paywallo PURCHASE] transaction event emission failed", err);
|
|
3920
4018
|
}
|
|
3921
4019
|
}
|
|
4020
|
+
/**
|
|
4021
|
+
* Emits `checkout_started` quando o usuário inicia a compra (toca em comprar),
|
|
4022
|
+
* antes do StoreKit/Billing abrir — conta mesmo que a sheet nativa seja cancelada.
|
|
4023
|
+
* Vira InitiateCheckout no Meta/TikTok. Fire-and-forget — uma falha de tracking
|
|
4024
|
+
* nunca pode travar a compra.
|
|
4025
|
+
*/
|
|
4026
|
+
async emitCheckoutStarted(productId) {
|
|
4027
|
+
try {
|
|
4028
|
+
const apiClient = this.getApiClientFn();
|
|
4029
|
+
if (!apiClient) return;
|
|
4030
|
+
const distinctId = PaywalloClient.getDistinctId();
|
|
4031
|
+
if (!distinctId) return;
|
|
4032
|
+
const product = this.getProductFromCache(productId);
|
|
4033
|
+
const properties = {
|
|
4034
|
+
product_id: productId,
|
|
4035
|
+
amount: product?.priceValue ?? 0,
|
|
4036
|
+
currency: product?.currency ?? "USD"
|
|
4037
|
+
};
|
|
4038
|
+
await apiClient.trackEvent("checkout_started", distinctId, properties, void 0, {
|
|
4039
|
+
priority: "critical"
|
|
4040
|
+
});
|
|
4041
|
+
if (this.getDebug()) console.log("[Paywallo PURCHASE] emitted checkout_started", productId);
|
|
4042
|
+
} catch (err) {
|
|
4043
|
+
if (this.getDebug()) console.log("[Paywallo PURCHASE] checkout_started emission failed", err);
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
3922
4046
|
/**
|
|
3923
4047
|
* Forwards a native transaction update to the EventBatcher.
|
|
3924
4048
|
* Public so tests can exercise the wiring without a fake NativeEventEmitter.
|
|
@@ -3941,9 +4065,9 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
3941
4065
|
product_id: update.productId
|
|
3942
4066
|
};
|
|
3943
4067
|
if (update.type !== "canceled") {
|
|
3944
|
-
const
|
|
3945
|
-
const amount = update.amount ??
|
|
3946
|
-
const currency = update.currency ??
|
|
4068
|
+
const cached2 = this.getProductFromCache(update.productId);
|
|
4069
|
+
const amount = update.amount ?? cached2?.priceValue;
|
|
4070
|
+
const currency = update.currency ?? cached2?.currency;
|
|
3947
4071
|
if (typeof amount === "number" && amount > 0) properties.amount = amount;
|
|
3948
4072
|
if (currency) properties.currency = currency;
|
|
3949
4073
|
}
|
|
@@ -4122,10 +4246,10 @@ var init_OfflineQueueStorage = __esm({
|
|
|
4122
4246
|
init_NativeStorage();
|
|
4123
4247
|
init_QueueJournal();
|
|
4124
4248
|
OfflineQueueStorage = class {
|
|
4125
|
-
constructor(config, emit,
|
|
4249
|
+
constructor(config, emit, log2) {
|
|
4126
4250
|
this.config = config;
|
|
4127
4251
|
this.emit = emit;
|
|
4128
|
-
this.log =
|
|
4252
|
+
this.log = log2;
|
|
4129
4253
|
}
|
|
4130
4254
|
async loadFromStorage(queue) {
|
|
4131
4255
|
const { merged, recovered, hadJournal } = await mergeJournalIntoMain(
|
|
@@ -4489,11 +4613,11 @@ var init_types2 = __esm({
|
|
|
4489
4613
|
});
|
|
4490
4614
|
|
|
4491
4615
|
// src/core/network/NetworkMonitor.ts
|
|
4492
|
-
var
|
|
4616
|
+
var import_react_native17, NetworkMonitorClass, networkMonitor;
|
|
4493
4617
|
var init_NetworkMonitor = __esm({
|
|
4494
4618
|
"src/core/network/NetworkMonitor.ts"() {
|
|
4495
4619
|
"use strict";
|
|
4496
|
-
|
|
4620
|
+
import_react_native17 = require("react-native");
|
|
4497
4621
|
init_types2();
|
|
4498
4622
|
NetworkMonitorClass = class {
|
|
4499
4623
|
constructor() {
|
|
@@ -4522,7 +4646,7 @@ var init_NetworkMonitor = __esm({
|
|
|
4522
4646
|
}, this.config.checkInterval);
|
|
4523
4647
|
}
|
|
4524
4648
|
setupAppStateListener() {
|
|
4525
|
-
this.appStateSubscription =
|
|
4649
|
+
this.appStateSubscription = import_react_native17.AppState.addEventListener("change", (state) => {
|
|
4526
4650
|
if (state === "active") {
|
|
4527
4651
|
if (!this.checkIntervalId) {
|
|
4528
4652
|
this.checkIntervalId = setInterval(() => {
|
|
@@ -4744,6 +4868,7 @@ var init_QueueProcessor = __esm({
|
|
|
4744
4868
|
for (const item of batch) {
|
|
4745
4869
|
retryIds.add(item.id);
|
|
4746
4870
|
}
|
|
4871
|
+
console.error("[Paywallo:QUEUE] event batch network error \u2014 items will retry", { size: batch.length, error: error instanceof Error ? error.message : String(error) });
|
|
4747
4872
|
this.log("Event batch threw network error - will retry", {
|
|
4748
4873
|
size: batch.length,
|
|
4749
4874
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -4761,14 +4886,25 @@ var init_QueueProcessor = __esm({
|
|
|
4761
4886
|
await offlineQueue.removeItem(item.id);
|
|
4762
4887
|
failed++;
|
|
4763
4888
|
}
|
|
4889
|
+
const responseError = typeof response.data === "object" && response.data !== null && "error" in response.data ? response.data.error : void 0;
|
|
4890
|
+
const isDuplicate = typeof responseError === "string" && responseError.toUpperCase().includes("DUPLICATE");
|
|
4891
|
+
if (isDuplicate) {
|
|
4892
|
+
if (this.config.debug) {
|
|
4893
|
+
console.log("[Paywallo:QUEUE] event batch deduplicated by server \u2014 items dropped (benign)", { status: response.status, size: batch.length, error: responseError });
|
|
4894
|
+
}
|
|
4895
|
+
} else {
|
|
4896
|
+
console.error("[Paywallo:QUEUE] event batch failed PERMANENTLY (4xx) \u2014 items dropped", { status: response.status, size: batch.length, responseBody: typeof response.data === "string" ? response.data.slice(0, 1e3) : JSON.stringify(response.data).slice(0, 1e3), firstItemBody: typeof batch[0].body === "string" ? batch[0].body.slice(0, 1e3) : JSON.stringify(batch[0].body).slice(0, 1e3) });
|
|
4897
|
+
}
|
|
4764
4898
|
this.log("Event batch failed permanently (4xx) - removing from queue", {
|
|
4765
4899
|
status: response.status,
|
|
4766
|
-
size: batch.length
|
|
4900
|
+
size: batch.length,
|
|
4901
|
+
isDuplicate
|
|
4767
4902
|
});
|
|
4768
4903
|
} else {
|
|
4769
4904
|
for (const item of batch) {
|
|
4770
4905
|
retryIds.add(item.id);
|
|
4771
4906
|
}
|
|
4907
|
+
console.error("[Paywallo:QUEUE] event batch server error (5xx) \u2014 will retry", { status: response.status, size: batch.length });
|
|
4772
4908
|
this.log("Event batch failed with server error - will retry", {
|
|
4773
4909
|
status: response.status,
|
|
4774
4910
|
size: batch.length
|
|
@@ -4798,6 +4934,7 @@ var init_QueueProcessor = __esm({
|
|
|
4798
4934
|
skipRetry: false
|
|
4799
4935
|
});
|
|
4800
4936
|
} catch (error) {
|
|
4937
|
+
console.error("[Paywallo:QUEUE] individual item network error \u2014 will retry", { id: item.id, url: item.url, error: error instanceof Error ? error.message : String(error) });
|
|
4801
4938
|
this.log("Request threw network error - will retry", {
|
|
4802
4939
|
id: item.id,
|
|
4803
4940
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -4878,11 +5015,11 @@ var init_queue = __esm({
|
|
|
4878
5015
|
});
|
|
4879
5016
|
|
|
4880
5017
|
// src/domains/iap/IAPValidator.ts
|
|
4881
|
-
var
|
|
5018
|
+
var import_react_native18, IAPValidator;
|
|
4882
5019
|
var init_IAPValidator = __esm({
|
|
4883
5020
|
"src/domains/iap/IAPValidator.ts"() {
|
|
4884
5021
|
"use strict";
|
|
4885
|
-
|
|
5022
|
+
import_react_native18 = require("react-native");
|
|
4886
5023
|
init_PaywalloClient();
|
|
4887
5024
|
init_queue();
|
|
4888
5025
|
init_PurchaseError();
|
|
@@ -4908,7 +5045,7 @@ var init_IAPValidator = __esm({
|
|
|
4908
5045
|
async validateWithServer(purchase, productId, options) {
|
|
4909
5046
|
const apiClient = this.getApiClientFn();
|
|
4910
5047
|
const product = this.getProductFromCache(productId);
|
|
4911
|
-
const platform =
|
|
5048
|
+
const platform = import_react_native18.Platform.OS;
|
|
4912
5049
|
const distinctId = PaywalloClient.getDistinctId();
|
|
4913
5050
|
return this.validateWithRetry(
|
|
4914
5051
|
() => apiClient.validatePurchase(
|
|
@@ -4943,7 +5080,7 @@ var init_IAPValidator = __esm({
|
|
|
4943
5080
|
try {
|
|
4944
5081
|
const apiClient = this.getApiClientFn();
|
|
4945
5082
|
const product = this.getProductFromCache(productId);
|
|
4946
|
-
const platform =
|
|
5083
|
+
const platform = import_react_native18.Platform.OS;
|
|
4947
5084
|
const distinctId = PaywalloClient.getDistinctId();
|
|
4948
5085
|
const appKey = apiClient.getAppKey();
|
|
4949
5086
|
const body = {
|
|
@@ -4983,11 +5120,11 @@ function getIAPService() {
|
|
|
4983
5120
|
}
|
|
4984
5121
|
return _instance;
|
|
4985
5122
|
}
|
|
4986
|
-
var
|
|
5123
|
+
var import_react_native19, IAPService, _instance;
|
|
4987
5124
|
var init_IAPService = __esm({
|
|
4988
5125
|
"src/domains/iap/IAPService.ts"() {
|
|
4989
5126
|
"use strict";
|
|
4990
|
-
|
|
5127
|
+
import_react_native19 = require("react-native");
|
|
4991
5128
|
init_PaywalloClient();
|
|
4992
5129
|
init_IAPTransactionEmitter();
|
|
4993
5130
|
init_IAPValidator();
|
|
@@ -5094,6 +5231,7 @@ var init_IAPService = __esm({
|
|
|
5094
5231
|
this.purchaseInFlight = productId;
|
|
5095
5232
|
if (this.debug) console.log(`[Paywallo PURCHASE] starting ${productId}`);
|
|
5096
5233
|
try {
|
|
5234
|
+
void this.emitter.emitCheckoutStarted(productId);
|
|
5097
5235
|
const purchase = await nativeStoreKit.purchase(productId);
|
|
5098
5236
|
if (!purchase) {
|
|
5099
5237
|
if (this.debug) console.log(`[Paywallo PURCHASE] ${productId} cancelled`);
|
|
@@ -5136,7 +5274,7 @@ var init_IAPService = __esm({
|
|
|
5136
5274
|
const transactions = await nativeStoreKit.getActiveTransactions();
|
|
5137
5275
|
const apiClient = this.getApiClient();
|
|
5138
5276
|
const distinctId = PaywalloClient.getDistinctId();
|
|
5139
|
-
const platform =
|
|
5277
|
+
const platform = import_react_native19.Platform.OS;
|
|
5140
5278
|
const results = await Promise.allSettled(
|
|
5141
5279
|
transactions.map((tx) => {
|
|
5142
5280
|
const product = this.productsCache.get(tx.productId);
|
|
@@ -5194,11 +5332,11 @@ var init_IAPService = __esm({
|
|
|
5194
5332
|
|
|
5195
5333
|
// src/domains/paywall/usePaywallTracking.ts
|
|
5196
5334
|
function usePaywallTracking() {
|
|
5197
|
-
const trackClosed = (0,
|
|
5335
|
+
const trackClosed = (0, import_react5.useCallback)(async (opts) => {
|
|
5198
5336
|
await emitPaywallClosed(opts);
|
|
5199
5337
|
await stopHeartbeat();
|
|
5200
5338
|
}, []);
|
|
5201
|
-
const trackDismissed = (0,
|
|
5339
|
+
const trackDismissed = (0, import_react5.useCallback)(async (opts) => {
|
|
5202
5340
|
const presentedAt = Date.now() - Math.max(0, opts.duration_ms);
|
|
5203
5341
|
await trackClosed({
|
|
5204
5342
|
placement: opts.placement,
|
|
@@ -5210,17 +5348,17 @@ function usePaywallTracking() {
|
|
|
5210
5348
|
...opts.variantId && { variantId: opts.variantId }
|
|
5211
5349
|
});
|
|
5212
5350
|
}, [trackClosed]);
|
|
5213
|
-
const trackProductSelected = (0,
|
|
5351
|
+
const trackProductSelected = (0, import_react5.useCallback)((_opts) => {
|
|
5214
5352
|
}, []);
|
|
5215
|
-
const trackPurchased = (0,
|
|
5353
|
+
const trackPurchased = (0, import_react5.useCallback)(async (_opts) => {
|
|
5216
5354
|
}, []);
|
|
5217
5355
|
return { trackClosed, trackDismissed, trackProductSelected, trackPurchased };
|
|
5218
5356
|
}
|
|
5219
|
-
var
|
|
5357
|
+
var import_react5;
|
|
5220
5358
|
var init_usePaywallTracking = __esm({
|
|
5221
5359
|
"src/domains/paywall/usePaywallTracking.ts"() {
|
|
5222
5360
|
"use strict";
|
|
5223
|
-
|
|
5361
|
+
import_react5 = require("react");
|
|
5224
5362
|
init_emitPaywallClosed();
|
|
5225
5363
|
init_paywallHeartbeat();
|
|
5226
5364
|
}
|
|
@@ -5228,19 +5366,19 @@ var init_usePaywallTracking = __esm({
|
|
|
5228
5366
|
|
|
5229
5367
|
// src/domains/paywall/usePaywallActions.ts
|
|
5230
5368
|
function usePaywallActions(placement, paywallConfig, onResult, variantKey, campaignId, openAnim, variantId) {
|
|
5231
|
-
const [isPurchasing, setIsPurchasing] = (0,
|
|
5232
|
-
const isPurchasingRef = (0,
|
|
5233
|
-
const [isClosing, setIsClosing] = (0,
|
|
5234
|
-
const slideAnim = (0,
|
|
5235
|
-
const presentedAtRef = (0,
|
|
5236
|
-
const closedRef = (0,
|
|
5369
|
+
const [isPurchasing, setIsPurchasing] = (0, import_react6.useState)(false);
|
|
5370
|
+
const isPurchasingRef = (0, import_react6.useRef)(false);
|
|
5371
|
+
const [isClosing, setIsClosing] = (0, import_react6.useState)(false);
|
|
5372
|
+
const slideAnim = (0, import_react6.useRef)(new import_react_native20.Animated.Value(0)).current;
|
|
5373
|
+
const presentedAtRef = (0, import_react6.useRef)(Date.now());
|
|
5374
|
+
const closedRef = (0, import_react6.useRef)(false);
|
|
5237
5375
|
const { trackDismissed, trackProductSelected, trackPurchased } = usePaywallTracking();
|
|
5238
|
-
const closeWithReason = (0,
|
|
5376
|
+
const closeWithReason = (0, import_react6.useCallback)((reason, resultOverride) => {
|
|
5239
5377
|
if (closedRef.current) return;
|
|
5240
5378
|
closedRef.current = true;
|
|
5241
5379
|
const animTarget = openAnim ?? slideAnim;
|
|
5242
|
-
|
|
5243
|
-
toValue:
|
|
5380
|
+
import_react_native20.Animated.timing(animTarget, {
|
|
5381
|
+
toValue: import_react_native20.Dimensions.get("window").height,
|
|
5244
5382
|
duration: 350,
|
|
5245
5383
|
useNativeDriver: true
|
|
5246
5384
|
}).start(() => {
|
|
@@ -5254,13 +5392,13 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
5254
5392
|
onResult(resultOverride ?? { presented: true, purchased: false, cancelled: true, restored: false });
|
|
5255
5393
|
});
|
|
5256
5394
|
}, [openAnim, slideAnim, paywallConfig, placement, trackDismissed, variantKey, campaignId, variantId, onResult]);
|
|
5257
|
-
const handleClose = (0,
|
|
5395
|
+
const handleClose = (0, import_react6.useCallback)(() => {
|
|
5258
5396
|
if (isClosing) return;
|
|
5259
5397
|
setIsClosing(true);
|
|
5260
5398
|
closeWithReason("dismissed");
|
|
5261
5399
|
}, [isClosing, closeWithReason]);
|
|
5262
|
-
(0,
|
|
5263
|
-
const sub =
|
|
5400
|
+
(0, import_react6.useEffect)(() => {
|
|
5401
|
+
const sub = import_react_native20.AppState.addEventListener("change", (nextState) => {
|
|
5264
5402
|
if (isPurchasingRef.current) return;
|
|
5265
5403
|
if (nextState === "background" || nextState === "inactive") {
|
|
5266
5404
|
closeWithReason("backgrounded");
|
|
@@ -5268,13 +5406,13 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
5268
5406
|
});
|
|
5269
5407
|
return () => sub.remove();
|
|
5270
5408
|
}, [closeWithReason]);
|
|
5271
|
-
(0,
|
|
5409
|
+
(0, import_react6.useEffect)(() => {
|
|
5272
5410
|
const timer = setTimeout(() => {
|
|
5273
5411
|
closeWithReason("timeout");
|
|
5274
5412
|
}, PAYWALL_TIMEOUT_MS);
|
|
5275
5413
|
return () => clearTimeout(timer);
|
|
5276
5414
|
}, [closeWithReason]);
|
|
5277
|
-
const handlePurchase = (0,
|
|
5415
|
+
const handlePurchase = (0, import_react6.useCallback)(async (productId) => {
|
|
5278
5416
|
if (isPurchasing) return;
|
|
5279
5417
|
setIsPurchasing(true);
|
|
5280
5418
|
isPurchasingRef.current = true;
|
|
@@ -5304,7 +5442,7 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
5304
5442
|
setIsPurchasing(false);
|
|
5305
5443
|
}
|
|
5306
5444
|
}, [isPurchasing, onResult, paywallConfig, placement, trackDismissed, trackProductSelected, trackPurchased, variantKey, campaignId, variantId]);
|
|
5307
|
-
const handleRestore = (0,
|
|
5445
|
+
const handleRestore = (0, import_react6.useCallback)(async () => {
|
|
5308
5446
|
if (isPurchasing) return;
|
|
5309
5447
|
setIsPurchasing(true);
|
|
5310
5448
|
isPurchasingRef.current = true;
|
|
@@ -5328,12 +5466,12 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
|
|
|
5328
5466
|
}, [isPurchasing, onResult, paywallConfig, placement, trackDismissed, variantKey, campaignId, variantId]);
|
|
5329
5467
|
return { isPurchasing, slideAnim, handleClose, handlePurchase, handleRestore };
|
|
5330
5468
|
}
|
|
5331
|
-
var
|
|
5469
|
+
var import_react6, import_react_native20, PAYWALL_TIMEOUT_MS;
|
|
5332
5470
|
var init_usePaywallActions = __esm({
|
|
5333
5471
|
"src/domains/paywall/usePaywallActions.ts"() {
|
|
5334
5472
|
"use strict";
|
|
5335
|
-
|
|
5336
|
-
|
|
5473
|
+
import_react6 = require("react");
|
|
5474
|
+
import_react_native20 = require("react-native");
|
|
5337
5475
|
init_IAPService();
|
|
5338
5476
|
init_usePaywallTracking();
|
|
5339
5477
|
PAYWALL_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
@@ -5342,15 +5480,15 @@ var init_usePaywallActions = __esm({
|
|
|
5342
5480
|
|
|
5343
5481
|
// src/domains/paywall/usePaywallLoader.ts
|
|
5344
5482
|
function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts, variantKey, campaignId, variantId) {
|
|
5345
|
-
const [error, setError] = (0,
|
|
5346
|
-
const [paywallConfig, setPaywallConfig] = (0,
|
|
5347
|
-
const [products, setProducts] = (0,
|
|
5348
|
-
const preloadedConfigRef = (0,
|
|
5483
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
5484
|
+
const [paywallConfig, setPaywallConfig] = (0, import_react7.useState)(null);
|
|
5485
|
+
const [products, setProducts] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
|
|
5486
|
+
const preloadedConfigRef = (0, import_react7.useRef)(preloadedConfig);
|
|
5349
5487
|
preloadedConfigRef.current = preloadedConfig;
|
|
5350
|
-
const preloadedProductsRef = (0,
|
|
5488
|
+
const preloadedProductsRef = (0, import_react7.useRef)(preloadedProducts);
|
|
5351
5489
|
preloadedProductsRef.current = preloadedProducts;
|
|
5352
|
-
const trackingDoneRef = (0,
|
|
5353
|
-
(0,
|
|
5490
|
+
const trackingDoneRef = (0, import_react7.useRef)(false);
|
|
5491
|
+
(0, import_react7.useEffect)(() => {
|
|
5354
5492
|
if (!visible) {
|
|
5355
5493
|
trackingDoneRef.current = false;
|
|
5356
5494
|
return;
|
|
@@ -5435,11 +5573,11 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
5435
5573
|
}, [placement, visible, variantKey, campaignId, variantId]);
|
|
5436
5574
|
return { paywallConfig, products, error };
|
|
5437
5575
|
}
|
|
5438
|
-
var
|
|
5576
|
+
var import_react7;
|
|
5439
5577
|
var init_usePaywallLoader = __esm({
|
|
5440
5578
|
"src/domains/paywall/usePaywallLoader.ts"() {
|
|
5441
5579
|
"use strict";
|
|
5442
|
-
|
|
5580
|
+
import_react7 = require("react");
|
|
5443
5581
|
init_PaywalloClient();
|
|
5444
5582
|
init_IAPService();
|
|
5445
5583
|
init_PaywallError();
|
|
@@ -5452,11 +5590,11 @@ function ErrorFallback({ description, onRetry, onClose }) {
|
|
|
5452
5590
|
const title = overrides?.title ?? getSdkString("paywallErrorTitle");
|
|
5453
5591
|
const retryLabel = overrides?.retry ?? getSdkString("paywallRetryButton");
|
|
5454
5592
|
const closeLabel = overrides?.close ?? getSdkString("paywallCloseButton");
|
|
5455
|
-
return /* @__PURE__ */ (0,
|
|
5456
|
-
/* @__PURE__ */ (0,
|
|
5457
|
-
/* @__PURE__ */ (0,
|
|
5458
|
-
/* @__PURE__ */ (0,
|
|
5459
|
-
/* @__PURE__ */ (0,
|
|
5593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.View, { style: styles3.fallbackContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native21.View, { style: styles3.fallbackCard, children: [
|
|
5594
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Text, { style: styles3.fallbackTitle, children: title }),
|
|
5595
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Text, { style: styles3.fallbackDescription, children: description }),
|
|
5596
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Pressable, { style: styles3.retryButton, onPress: onRetry, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Text, { style: styles3.retryButtonText, children: retryLabel }) }),
|
|
5597
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Pressable, { style: styles3.closeButton, onPress: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Text, { style: styles3.closeButtonText, children: closeLabel }) })
|
|
5460
5598
|
] }) });
|
|
5461
5599
|
}
|
|
5462
5600
|
function PaywallModal({
|
|
@@ -5478,18 +5616,20 @@ function PaywallModal({
|
|
|
5478
5616
|
campaignId,
|
|
5479
5617
|
variantId
|
|
5480
5618
|
);
|
|
5481
|
-
const screenHeight =
|
|
5482
|
-
const openAnim = (0,
|
|
5483
|
-
const [modalVisible, setModalVisible] = (0,
|
|
5484
|
-
const handleResult = (0,
|
|
5619
|
+
const screenHeight = import_react_native21.Dimensions.get("window").height;
|
|
5620
|
+
const openAnim = (0, import_react8.useRef)(new import_react_native21.Animated.Value(screenHeight)).current;
|
|
5621
|
+
const [modalVisible, setModalVisible] = (0, import_react8.useState)(false);
|
|
5622
|
+
const handleResult = (0, import_react8.useCallback)((result) => {
|
|
5485
5623
|
setModalVisible(false);
|
|
5486
5624
|
onResult(result);
|
|
5487
5625
|
}, [onResult]);
|
|
5488
5626
|
const { isPurchasing, slideAnim, handleClose, handlePurchase, handleRestore } = usePaywallActions(placement, paywallConfig, handleResult, variantKey, campaignId, openAnim, variantId);
|
|
5489
|
-
const [webViewError, setWebViewError] = (0,
|
|
5490
|
-
const [retryCount, setRetryCount] = (0,
|
|
5491
|
-
const
|
|
5492
|
-
const
|
|
5627
|
+
const [webViewError, setWebViewError] = (0, import_react8.useState)(null);
|
|
5628
|
+
const [retryCount, setRetryCount] = (0, import_react8.useState)(0);
|
|
5629
|
+
const [showSkeleton, setShowSkeleton] = (0, import_react8.useState)(true);
|
|
5630
|
+
const skeletonOpacity = (0, import_react8.useRef)(new import_react_native21.Animated.Value(1)).current;
|
|
5631
|
+
const retryCountRef = (0, import_react8.useRef)(0);
|
|
5632
|
+
const handleWebViewError = (0, import_react8.useCallback)(
|
|
5493
5633
|
(err) => {
|
|
5494
5634
|
if (retryCountRef.current >= 1) {
|
|
5495
5635
|
setWebViewError({ code: err.code, description: err.description });
|
|
@@ -5500,26 +5640,44 @@ function PaywallModal({
|
|
|
5500
5640
|
},
|
|
5501
5641
|
[]
|
|
5502
5642
|
);
|
|
5503
|
-
const handleRetry = (0,
|
|
5643
|
+
const handleRetry = (0, import_react8.useCallback)(() => {
|
|
5504
5644
|
retryCountRef.current = 0;
|
|
5505
5645
|
setWebViewError(null);
|
|
5506
5646
|
setRetryCount(0);
|
|
5507
|
-
|
|
5508
|
-
|
|
5647
|
+
setShowSkeleton(true);
|
|
5648
|
+
skeletonOpacity.setValue(1);
|
|
5649
|
+
}, [skeletonOpacity]);
|
|
5650
|
+
const handleWebViewReady = (0, import_react8.useCallback)(() => {
|
|
5651
|
+
import_react_native21.Animated.timing(skeletonOpacity, {
|
|
5652
|
+
toValue: 0,
|
|
5653
|
+
duration: 250,
|
|
5654
|
+
easing: import_react_native21.Easing.out(import_react_native21.Easing.cubic),
|
|
5655
|
+
useNativeDriver: true
|
|
5656
|
+
}).start(() => setShowSkeleton(false));
|
|
5657
|
+
}, [skeletonOpacity]);
|
|
5658
|
+
(0, import_react8.useEffect)(() => {
|
|
5659
|
+
if (!visible || !showSkeleton) return;
|
|
5660
|
+
const timer = setTimeout(handleWebViewReady, 8e3);
|
|
5661
|
+
return () => clearTimeout(timer);
|
|
5662
|
+
}, [visible, showSkeleton, handleWebViewReady]);
|
|
5663
|
+
(0, import_react8.useEffect)(() => {
|
|
5509
5664
|
if (visible) {
|
|
5510
5665
|
setModalVisible(true);
|
|
5511
|
-
|
|
5512
|
-
|
|
5666
|
+
setShowSkeleton(true);
|
|
5667
|
+
skeletonOpacity.setValue(1);
|
|
5668
|
+
openAnim.setValue(import_react_native21.Dimensions.get("window").height);
|
|
5669
|
+
import_react_native21.Animated.timing(openAnim, {
|
|
5513
5670
|
toValue: 0,
|
|
5514
5671
|
duration: 550,
|
|
5515
|
-
easing:
|
|
5672
|
+
easing: import_react_native21.Easing.out(import_react_native21.Easing.cubic),
|
|
5516
5673
|
useNativeDriver: true
|
|
5517
5674
|
}).start();
|
|
5518
5675
|
}
|
|
5519
|
-
}, [visible, openAnim]);
|
|
5676
|
+
}, [visible, openAnim, skeletonOpacity]);
|
|
5520
5677
|
if (!modalVisible && !visible) return null;
|
|
5521
|
-
|
|
5522
|
-
|
|
5678
|
+
const skeletonBackground = paywallConfig && "craftData" in paywallConfig.config ? extractFirstPageBackground(paywallConfig.config.craftData) : "#FFFFFF";
|
|
5679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5680
|
+
import_react_native21.Modal,
|
|
5523
5681
|
{
|
|
5524
5682
|
visible: modalVisible,
|
|
5525
5683
|
animationType: "none",
|
|
@@ -5527,16 +5685,16 @@ function PaywallModal({
|
|
|
5527
5685
|
onRequestClose: handleClose,
|
|
5528
5686
|
transparent: true,
|
|
5529
5687
|
statusBarTranslucent: true,
|
|
5530
|
-
children: /* @__PURE__ */ (0,
|
|
5531
|
-
error && /* @__PURE__ */ (0,
|
|
5532
|
-
!error && paywallConfig && "craftData" in paywallConfig.config && /* @__PURE__ */ (0,
|
|
5688
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.View, { style: styles3.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Animated.View, { style: [styles3.animatedContainer, { transform: [{ translateY: openAnim }] }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native21.View, { style: styles3.container, children: [
|
|
5689
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.View, { style: styles3.errorContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native21.Text, { style: styles3.errorText, children: error.message }) }),
|
|
5690
|
+
!error && paywallConfig && "craftData" in paywallConfig.config && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: webViewError ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5533
5691
|
ErrorFallback,
|
|
5534
5692
|
{
|
|
5535
5693
|
description: webViewError.description,
|
|
5536
5694
|
onRetry: handleRetry,
|
|
5537
5695
|
onClose: handleClose
|
|
5538
5696
|
}
|
|
5539
|
-
) : /* @__PURE__ */ (0,
|
|
5697
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5540
5698
|
PaywallWebView,
|
|
5541
5699
|
{
|
|
5542
5700
|
paywallId: paywallConfig.id,
|
|
@@ -5545,30 +5703,41 @@ function PaywallModal({
|
|
|
5545
5703
|
primaryProductId: paywallConfig.primaryProductId,
|
|
5546
5704
|
secondaryProductId: paywallConfig.secondaryProductId,
|
|
5547
5705
|
isPurchasing,
|
|
5706
|
+
onReady: handleWebViewReady,
|
|
5548
5707
|
onClose: handleClose,
|
|
5549
5708
|
onPurchase: handlePurchase,
|
|
5550
5709
|
onRestore: handleRestore,
|
|
5551
5710
|
onError: handleWebViewError
|
|
5552
5711
|
},
|
|
5553
5712
|
retryCount
|
|
5554
|
-
) })
|
|
5713
|
+
) }),
|
|
5714
|
+
showSkeleton && !error && !webViewError && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5715
|
+
import_react_native21.Animated.View,
|
|
5716
|
+
{
|
|
5717
|
+
style: [import_react_native21.StyleSheet.absoluteFill, { opacity: skeletonOpacity }],
|
|
5718
|
+
pointerEvents: "none",
|
|
5719
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaywallSkeleton, { backgroundColor: skeletonBackground })
|
|
5720
|
+
}
|
|
5721
|
+
)
|
|
5555
5722
|
] }) }) })
|
|
5556
5723
|
}
|
|
5557
5724
|
);
|
|
5558
5725
|
}
|
|
5559
|
-
var
|
|
5726
|
+
var import_react8, import_react_native21, import_jsx_runtime3, styles3;
|
|
5560
5727
|
var init_PaywallModal = __esm({
|
|
5561
5728
|
"src/domains/paywall/PaywallModal.tsx"() {
|
|
5562
5729
|
"use strict";
|
|
5563
|
-
|
|
5564
|
-
|
|
5730
|
+
import_react8 = require("react");
|
|
5731
|
+
import_react_native21 = require("react-native");
|
|
5565
5732
|
init_PaywalloClient();
|
|
5566
5733
|
init_localization();
|
|
5734
|
+
init_extractFirstPageBackground();
|
|
5735
|
+
init_PaywallSkeleton();
|
|
5567
5736
|
init_PaywallWebView();
|
|
5568
5737
|
init_usePaywallActions();
|
|
5569
5738
|
init_usePaywallLoader();
|
|
5570
|
-
|
|
5571
|
-
|
|
5739
|
+
import_jsx_runtime3 = require("react/jsx-runtime");
|
|
5740
|
+
styles3 = import_react_native21.StyleSheet.create({
|
|
5572
5741
|
overlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.3)" },
|
|
5573
5742
|
animatedContainer: { flex: 1, backgroundColor: "#fff" },
|
|
5574
5743
|
container: { flex: 1, backgroundColor: "#fff" },
|
|
@@ -5624,12 +5793,175 @@ var init_PaywallModal = __esm({
|
|
|
5624
5793
|
}
|
|
5625
5794
|
});
|
|
5626
5795
|
|
|
5796
|
+
// src/domains/paywall/PaywallPreloadService.ts
|
|
5797
|
+
var PRELOAD_TTL_MS, STALE_THRESHOLD, PaywallPreloadService, paywallPreloadService;
|
|
5798
|
+
var init_PaywallPreloadService = __esm({
|
|
5799
|
+
"src/domains/paywall/PaywallPreloadService.ts"() {
|
|
5800
|
+
"use strict";
|
|
5801
|
+
init_PaywalloClient();
|
|
5802
|
+
init_IAPService();
|
|
5803
|
+
init_PaywallError();
|
|
5804
|
+
PRELOAD_TTL_MS = 5 * 60 * 1e3;
|
|
5805
|
+
STALE_THRESHOLD = 0.75;
|
|
5806
|
+
PaywallPreloadService = class {
|
|
5807
|
+
constructor() {
|
|
5808
|
+
this.preloaded = /* @__PURE__ */ new Map();
|
|
5809
|
+
this.activePreloads = /* @__PURE__ */ new Map();
|
|
5810
|
+
this.apiClientRef = null;
|
|
5811
|
+
}
|
|
5812
|
+
async preload(apiClient, placement) {
|
|
5813
|
+
this.apiClientRef = apiClient;
|
|
5814
|
+
const existing = this.activePreloads.get(placement);
|
|
5815
|
+
if (existing) return existing;
|
|
5816
|
+
const promise = this.doPreload(apiClient, placement);
|
|
5817
|
+
this.activePreloads.set(placement, promise);
|
|
5818
|
+
try {
|
|
5819
|
+
return await promise;
|
|
5820
|
+
} finally {
|
|
5821
|
+
this.activePreloads.delete(placement);
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
async preloadMany(apiClient, placements) {
|
|
5825
|
+
this.apiClientRef = apiClient;
|
|
5826
|
+
if (placements.length === 0) return;
|
|
5827
|
+
const debug = PaywalloClient.getConfig()?.debug;
|
|
5828
|
+
if (debug) console.log(`[Paywallo PRELOAD] paywalls: ${placements.length} placements`);
|
|
5829
|
+
for (let i = 0; i < placements.length; i++) {
|
|
5830
|
+
if (i > 0) await new Promise((r) => setTimeout(r, 200));
|
|
5831
|
+
void this.preload(apiClient, placements[i]).catch((err) => {
|
|
5832
|
+
if (debug) console.log(`[Paywallo PRELOAD] paywall failed ${placements[i]}:`, err);
|
|
5833
|
+
});
|
|
5834
|
+
}
|
|
5835
|
+
}
|
|
5836
|
+
getPreloaded(placement) {
|
|
5837
|
+
const cached2 = this.preloaded.get(placement);
|
|
5838
|
+
if (!cached2) return null;
|
|
5839
|
+
const age = Date.now() - cached2.preloadedAt;
|
|
5840
|
+
if (age >= PRELOAD_TTL_MS) {
|
|
5841
|
+
this.preloaded.delete(placement);
|
|
5842
|
+
return null;
|
|
5843
|
+
}
|
|
5844
|
+
if (age >= PRELOAD_TTL_MS * STALE_THRESHOLD && this.apiClientRef) {
|
|
5845
|
+
void this.preload(this.apiClientRef, placement).catch(() => {
|
|
5846
|
+
});
|
|
5847
|
+
}
|
|
5848
|
+
return { config: cached2.config, products: new Map(cached2.products) };
|
|
5849
|
+
}
|
|
5850
|
+
isPreloaded(placement) {
|
|
5851
|
+
return this.getPreloaded(placement) !== null;
|
|
5852
|
+
}
|
|
5853
|
+
clear() {
|
|
5854
|
+
this.preloaded.clear();
|
|
5855
|
+
this.activePreloads.clear();
|
|
5856
|
+
}
|
|
5857
|
+
async doPreload(apiClient, placement) {
|
|
5858
|
+
try {
|
|
5859
|
+
const config = await apiClient.getPaywall(placement);
|
|
5860
|
+
if (!config) {
|
|
5861
|
+
return {
|
|
5862
|
+
success: false,
|
|
5863
|
+
error: new PaywallError(
|
|
5864
|
+
PAYWALL_ERROR_CODES.NOT_FOUND,
|
|
5865
|
+
`Paywall not found for placement: ${placement}`
|
|
5866
|
+
)
|
|
5867
|
+
};
|
|
5868
|
+
}
|
|
5869
|
+
const products = await this.loadProductsFor(config);
|
|
5870
|
+
this.preloaded.set(placement, { config, products, preloadedAt: Date.now() });
|
|
5871
|
+
if (PaywalloClient.getConfig()?.debug) {
|
|
5872
|
+
console.log(`[Paywallo PRELOAD] paywall cached \u2014 placement: ${placement}`);
|
|
5873
|
+
}
|
|
5874
|
+
return { success: true };
|
|
5875
|
+
} catch (error) {
|
|
5876
|
+
return {
|
|
5877
|
+
success: false,
|
|
5878
|
+
error: error instanceof Error ? error : new PaywallError(PAYWALL_ERROR_CODES.LOAD_FAILED, String(error))
|
|
5879
|
+
};
|
|
5880
|
+
}
|
|
5881
|
+
}
|
|
5882
|
+
async loadProductsFor(config) {
|
|
5883
|
+
const productIds = [];
|
|
5884
|
+
if (config.primaryProductId) productIds.push(config.primaryProductId);
|
|
5885
|
+
if (config.secondaryProductId) productIds.push(config.secondaryProductId);
|
|
5886
|
+
if (productIds.length === 0) return /* @__PURE__ */ new Map();
|
|
5887
|
+
try {
|
|
5888
|
+
const loaded = await getIAPService().loadProducts(productIds);
|
|
5889
|
+
const map = /* @__PURE__ */ new Map();
|
|
5890
|
+
for (const p of loaded) map.set(p.productId, p);
|
|
5891
|
+
return map;
|
|
5892
|
+
} catch (err) {
|
|
5893
|
+
if (PaywalloClient.getConfig()?.debug) {
|
|
5894
|
+
console.log("[Paywallo PRELOAD] products failed, caching config only:", err);
|
|
5895
|
+
}
|
|
5896
|
+
return /* @__PURE__ */ new Map();
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
};
|
|
5900
|
+
paywallPreloadService = new PaywallPreloadService();
|
|
5901
|
+
}
|
|
5902
|
+
});
|
|
5903
|
+
|
|
5904
|
+
// src/domains/paywall/PaywallWebViewPrewarmer.tsx
|
|
5905
|
+
function getNativeWebView2() {
|
|
5906
|
+
if (NativeWebViewComponent2) return NativeWebViewComponent2;
|
|
5907
|
+
if (nativeLookupFailed) return null;
|
|
5908
|
+
try {
|
|
5909
|
+
NativeWebViewComponent2 = (0, import_react_native22.requireNativeComponent)("PaywalloWebView");
|
|
5910
|
+
return NativeWebViewComponent2;
|
|
5911
|
+
} catch {
|
|
5912
|
+
nativeLookupFailed = true;
|
|
5913
|
+
return null;
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
function PaywallWebViewPrewarmer({
|
|
5917
|
+
webUrl,
|
|
5918
|
+
durationMs = DEFAULT_DURATION_MS
|
|
5919
|
+
}) {
|
|
5920
|
+
const NativeWebView = (0, import_react9.useMemo)(() => getNativeWebView2(), []);
|
|
5921
|
+
const [mounted, setMounted] = (0, import_react9.useState)(true);
|
|
5922
|
+
(0, import_react9.useEffect)(() => {
|
|
5923
|
+
if (!NativeWebView) return;
|
|
5924
|
+
const timer = setTimeout(() => setMounted(false), durationMs);
|
|
5925
|
+
return () => clearTimeout(timer);
|
|
5926
|
+
}, [NativeWebView, durationMs]);
|
|
5927
|
+
if (!NativeWebView || !mounted) return null;
|
|
5928
|
+
const preheatUrl = `${webUrl}/paywall/preheat`;
|
|
5929
|
+
if (PaywalloClient.getConfig()?.debug) {
|
|
5930
|
+
console.log(`[Paywallo PREWARM] mounting hidden WebView: ${preheatUrl}`);
|
|
5931
|
+
}
|
|
5932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native22.View, { pointerEvents: "none", style: styles4.hidden, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NativeWebView, { sourceUrl: preheatUrl, style: styles4.fill }) });
|
|
5933
|
+
}
|
|
5934
|
+
var import_react9, import_react_native22, import_jsx_runtime4, NativeWebViewComponent2, nativeLookupFailed, DEFAULT_DURATION_MS, styles4;
|
|
5935
|
+
var init_PaywallWebViewPrewarmer = __esm({
|
|
5936
|
+
"src/domains/paywall/PaywallWebViewPrewarmer.tsx"() {
|
|
5937
|
+
"use strict";
|
|
5938
|
+
import_react9 = require("react");
|
|
5939
|
+
import_react_native22 = require("react-native");
|
|
5940
|
+
init_PaywalloClient();
|
|
5941
|
+
import_jsx_runtime4 = require("react/jsx-runtime");
|
|
5942
|
+
NativeWebViewComponent2 = null;
|
|
5943
|
+
nativeLookupFailed = false;
|
|
5944
|
+
DEFAULT_DURATION_MS = 60 * 1e3;
|
|
5945
|
+
styles4 = import_react_native22.StyleSheet.create({
|
|
5946
|
+
hidden: {
|
|
5947
|
+
height: 1,
|
|
5948
|
+
left: -9999,
|
|
5949
|
+
opacity: 0,
|
|
5950
|
+
position: "absolute",
|
|
5951
|
+
top: -9999,
|
|
5952
|
+
width: 1
|
|
5953
|
+
},
|
|
5954
|
+
fill: { flex: 1 }
|
|
5955
|
+
});
|
|
5956
|
+
}
|
|
5957
|
+
});
|
|
5958
|
+
|
|
5627
5959
|
// src/domains/paywall/usePaywallSession.ts
|
|
5628
5960
|
function usePaywallSession(options) {
|
|
5629
|
-
const closedRef = (0,
|
|
5630
|
-
const optsRef = (0,
|
|
5961
|
+
const closedRef = (0, import_react10.useRef)(false);
|
|
5962
|
+
const optsRef = (0, import_react10.useRef)(options);
|
|
5631
5963
|
optsRef.current = options;
|
|
5632
|
-
(0,
|
|
5964
|
+
(0, import_react10.useEffect)(() => {
|
|
5633
5965
|
if (!options) return;
|
|
5634
5966
|
closedRef.current = false;
|
|
5635
5967
|
startHeartbeat({
|
|
@@ -5659,16 +5991,16 @@ function usePaywallSession(options) {
|
|
|
5659
5991
|
});
|
|
5660
5992
|
};
|
|
5661
5993
|
}, [options?.paywallId, options?.placement]);
|
|
5662
|
-
const markClosed = (0,
|
|
5994
|
+
const markClosed = (0, import_react10.useCallback)(() => {
|
|
5663
5995
|
closedRef.current = true;
|
|
5664
5996
|
}, []);
|
|
5665
5997
|
return { markClosed };
|
|
5666
5998
|
}
|
|
5667
|
-
var
|
|
5999
|
+
var import_react10;
|
|
5668
6000
|
var init_usePaywallSession = __esm({
|
|
5669
6001
|
"src/domains/paywall/usePaywallSession.ts"() {
|
|
5670
6002
|
"use strict";
|
|
5671
|
-
|
|
6003
|
+
import_react10 = require("react");
|
|
5672
6004
|
init_emitPaywallClosed();
|
|
5673
6005
|
init_paywallHeartbeat();
|
|
5674
6006
|
}
|
|
@@ -5676,9 +6008,9 @@ var init_usePaywallSession = __esm({
|
|
|
5676
6008
|
|
|
5677
6009
|
// src/domains/paywall/usePaywallPresenter.ts
|
|
5678
6010
|
function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
5679
|
-
const [showingPreloadedWebView, setShowingPreloadedWebView] = (0,
|
|
5680
|
-
const resolverRef = (0,
|
|
5681
|
-
const presentedAtRef = (0,
|
|
6011
|
+
const [showingPreloadedWebView, setShowingPreloadedWebView] = (0, import_react11.useState)(false);
|
|
6012
|
+
const resolverRef = (0, import_react11.useRef)(null);
|
|
6013
|
+
const presentedAtRef = (0, import_react11.useRef)(Date.now());
|
|
5682
6014
|
const sessionOpts = showingPreloadedWebView && preloadedWebView ? {
|
|
5683
6015
|
placement: preloadedWebView.placement,
|
|
5684
6016
|
paywallId: preloadedWebView.paywallId,
|
|
@@ -5688,7 +6020,7 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
5688
6020
|
...preloadedWebView.campaignId && { campaignId: preloadedWebView.campaignId }
|
|
5689
6021
|
} : null;
|
|
5690
6022
|
const { markClosed } = usePaywallSession(sessionOpts);
|
|
5691
|
-
(0,
|
|
6023
|
+
(0, import_react11.useEffect)(() => {
|
|
5692
6024
|
return () => {
|
|
5693
6025
|
if (resolverRef.current) {
|
|
5694
6026
|
resolverRef.current({ presented: false, purchased: false, cancelled: true, restored: false });
|
|
@@ -5697,7 +6029,7 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
5697
6029
|
setShowingPreloadedWebView(false);
|
|
5698
6030
|
};
|
|
5699
6031
|
}, []);
|
|
5700
|
-
const presentPreloadedWebView = (0,
|
|
6032
|
+
const presentPreloadedWebView = (0, import_react11.useCallback)(() => {
|
|
5701
6033
|
return new Promise((resolve) => {
|
|
5702
6034
|
resolverRef.current = resolve;
|
|
5703
6035
|
presentedAtRef.current = Date.now();
|
|
@@ -5731,16 +6063,16 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
5731
6063
|
}
|
|
5732
6064
|
});
|
|
5733
6065
|
}, [preloadedWebView]);
|
|
5734
|
-
const resolvePreloadedPaywall = (0,
|
|
6066
|
+
const resolvePreloadedPaywall = (0, import_react11.useCallback)((result) => {
|
|
5735
6067
|
if (resolverRef.current) {
|
|
5736
6068
|
resolverRef.current(result);
|
|
5737
6069
|
resolverRef.current = null;
|
|
5738
6070
|
}
|
|
5739
6071
|
}, []);
|
|
5740
|
-
const handlePreloadedWebViewReady = (0,
|
|
6072
|
+
const handlePreloadedWebViewReady = (0, import_react11.useCallback)(() => {
|
|
5741
6073
|
setPreloadedWebView((prev) => prev ? { ...prev, loaded: true } : null);
|
|
5742
6074
|
}, [setPreloadedWebView]);
|
|
5743
|
-
const handlePreloadedClose = (0,
|
|
6075
|
+
const handlePreloadedClose = (0, import_react11.useCallback)(() => {
|
|
5744
6076
|
if (preloadedWebView) {
|
|
5745
6077
|
markClosed();
|
|
5746
6078
|
void emitPaywallClosed({
|
|
@@ -5758,11 +6090,11 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
5758
6090
|
}, [preloadedWebView, markClosed, resolvePreloadedPaywall]);
|
|
5759
6091
|
return { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady, handlePreloadedClose, setShowingPreloadedWebView, presentedAtRef };
|
|
5760
6092
|
}
|
|
5761
|
-
var
|
|
6093
|
+
var import_react11;
|
|
5762
6094
|
var init_usePaywallPresenter = __esm({
|
|
5763
6095
|
"src/domains/paywall/usePaywallPresenter.ts"() {
|
|
5764
6096
|
"use strict";
|
|
5765
|
-
|
|
6097
|
+
import_react11 = require("react");
|
|
5766
6098
|
init_PaywalloClient();
|
|
5767
6099
|
init_emitPaywallClosed();
|
|
5768
6100
|
init_usePaywallSession();
|
|
@@ -5777,7 +6109,9 @@ var init_paywall = __esm({
|
|
|
5777
6109
|
init_PaywallError();
|
|
5778
6110
|
init_PaywallErrorBoundary();
|
|
5779
6111
|
init_PaywallModal();
|
|
6112
|
+
init_PaywallPreloadService();
|
|
5780
6113
|
init_PaywallWebView();
|
|
6114
|
+
init_PaywallWebViewPrewarmer();
|
|
5781
6115
|
init_usePaywallPresenter();
|
|
5782
6116
|
init_usePaywallTracking();
|
|
5783
6117
|
}
|
|
@@ -5883,10 +6217,10 @@ var init_PlanService = __esm({
|
|
|
5883
6217
|
}
|
|
5884
6218
|
async getCurrentPlan(forceRefresh = false) {
|
|
5885
6219
|
if (!forceRefresh) {
|
|
5886
|
-
const
|
|
5887
|
-
if (
|
|
5888
|
-
const current =
|
|
5889
|
-
(p) => p.identifier ===
|
|
6220
|
+
const cached2 = this.cache.get();
|
|
6221
|
+
if (cached2 && !cached2.isStale) {
|
|
6222
|
+
const current = cached2.data.plans.find(
|
|
6223
|
+
(p) => p.identifier === cached2.data.currentIdentifier
|
|
5890
6224
|
);
|
|
5891
6225
|
return current ?? null;
|
|
5892
6226
|
}
|
|
@@ -5913,8 +6247,8 @@ var init_PlanService = __esm({
|
|
|
5913
6247
|
}
|
|
5914
6248
|
async getAllPlans(forceRefresh = false) {
|
|
5915
6249
|
if (!forceRefresh) {
|
|
5916
|
-
const
|
|
5917
|
-
if (
|
|
6250
|
+
const cached2 = this.cache.get();
|
|
6251
|
+
if (cached2 && !cached2.isStale) return cached2.data;
|
|
5918
6252
|
}
|
|
5919
6253
|
if (!this.cache.get()) {
|
|
5920
6254
|
try {
|
|
@@ -6032,95 +6366,257 @@ var init_analytics = __esm({
|
|
|
6032
6366
|
}
|
|
6033
6367
|
});
|
|
6034
6368
|
|
|
6035
|
-
// src/core/
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
}
|
|
6040
|
-
async function trackEvent(apiClient, state, eventName, options) {
|
|
6041
|
-
const distinctId = identityManager.getDistinctId();
|
|
6042
|
-
if (!distinctId) {
|
|
6043
|
-
if (state.config?.debug) console.log(`[Paywallo TRACK] ${eventName} skipped (no distinctId)`);
|
|
6044
|
-
return;
|
|
6045
|
-
}
|
|
6046
|
-
if (!isValidEventName(eventName)) {
|
|
6047
|
-
const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
|
|
6048
|
-
throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
|
|
6049
|
-
}
|
|
6050
|
-
if (state.config?.debug && eventName.startsWith("$purchase")) console.log(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
6051
|
-
const sessionId = sessionManager.getSessionId();
|
|
6052
|
-
await apiClient.trackEvent(
|
|
6053
|
-
eventName,
|
|
6054
|
-
distinctId,
|
|
6055
|
-
{ ...identityManager.getProperties(), ...options?.properties, ...sessionId && { sessionId } },
|
|
6056
|
-
options?.timestamp,
|
|
6057
|
-
options?.priority ? { priority: options.priority } : void 0
|
|
6058
|
-
);
|
|
6059
|
-
}
|
|
6060
|
-
async function trackOnboardingStep(apiClient, state, index, name) {
|
|
6061
|
-
const distinctId = identityManager.getDistinctId();
|
|
6062
|
-
if (!distinctId) return;
|
|
6063
|
-
if (!Number.isInteger(index) || index < 0) {
|
|
6064
|
-
const msg = `Invalid stepIndex: "${index}". Must be a non-negative integer.`;
|
|
6065
|
-
throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_STEP_INDEX, msg);
|
|
6066
|
-
}
|
|
6067
|
-
const now = Date.now();
|
|
6068
|
-
const timeOnPreviousStep = state.lastOnboardingStepTimestamp !== null ? Math.round((now - state.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
6069
|
-
state.lastOnboardingStepTimestamp = now;
|
|
6070
|
-
await apiClient.trackEvent("$onboarding_step", distinctId, { stepIndex: index, stepName: name, timeOnPreviousStep });
|
|
6071
|
-
}
|
|
6072
|
-
function validateCoreAction(actionName) {
|
|
6073
|
-
if (!actionName || typeof actionName !== "string") {
|
|
6074
|
-
const msg = `Invalid actionName: "${actionName}". Must be a non-empty string.`;
|
|
6075
|
-
throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_ACTION_NAME, msg);
|
|
6076
|
-
}
|
|
6077
|
-
}
|
|
6078
|
-
var init_PaywalloAnalytics = __esm({
|
|
6079
|
-
"src/core/PaywalloAnalytics.ts"() {
|
|
6369
|
+
// src/core/events/schemas.ts
|
|
6370
|
+
var import_zod, lifecycleEventSchema, identifyEventSchema, paywallEventSchema, transactionEventSchema, onboardingEventSchema, notificationEventSchema, customEventSchema, EVENT_SCHEMAS;
|
|
6371
|
+
var init_schemas = __esm({
|
|
6372
|
+
"src/core/events/schemas.ts"() {
|
|
6080
6373
|
"use strict";
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6374
|
+
import_zod = require("zod");
|
|
6375
|
+
lifecycleEventSchema = import_zod.z.object({
|
|
6376
|
+
type: import_zod.z.enum([
|
|
6377
|
+
"install",
|
|
6378
|
+
"cold_start",
|
|
6379
|
+
"foreground",
|
|
6380
|
+
"background",
|
|
6381
|
+
"session_start",
|
|
6382
|
+
"session_end"
|
|
6383
|
+
]),
|
|
6384
|
+
session_id: import_zod.z.string().optional(),
|
|
6385
|
+
duration_s: import_zod.z.number().nonnegative().optional(),
|
|
6386
|
+
first_ever: import_zod.z.boolean().optional(),
|
|
6387
|
+
// Contexto leve transportado em lifecycle (útil pra cold_start/install)
|
|
6388
|
+
app_version: import_zod.z.string().optional(),
|
|
6389
|
+
device_type: import_zod.z.enum(["ios", "android"]).optional(),
|
|
6390
|
+
os_version: import_zod.z.string().optional(),
|
|
6391
|
+
// Timestamps opcionais — o EventBatcher injeta `timestamp` no envelope
|
|
6392
|
+
started_at: import_zod.z.string().optional(),
|
|
6393
|
+
ended_at: import_zod.z.string().optional()
|
|
6394
|
+
}).strict();
|
|
6395
|
+
identifyEventSchema = import_zod.z.object({
|
|
6396
|
+
distinct_id: import_zod.z.string().min(1),
|
|
6397
|
+
email: import_zod.z.email().optional(),
|
|
6398
|
+
traits: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
6399
|
+
attribution: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
6400
|
+
device: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
6401
|
+
}).strict();
|
|
6402
|
+
paywallEventSchema = import_zod.z.object({
|
|
6403
|
+
type: import_zod.z.enum(["viewed", "closed", "purchased"]),
|
|
6404
|
+
paywall_id: import_zod.z.string().min(1),
|
|
6405
|
+
placement: import_zod.z.string().optional(),
|
|
6406
|
+
variant_id: import_zod.z.string().optional(),
|
|
6407
|
+
variant_key: import_zod.z.string().optional(),
|
|
6408
|
+
campaign_id: import_zod.z.string().optional(),
|
|
6409
|
+
// `closed`-specific
|
|
6410
|
+
closed_at: import_zod.z.string().optional(),
|
|
6411
|
+
duration_s: import_zod.z.number().nonnegative().optional(),
|
|
6412
|
+
close_reason: import_zod.z.enum(["dismiss", "cta", "purchase", "error", "timeout"]).optional(),
|
|
6413
|
+
scroll_depth: import_zod.z.number().min(0).max(1).optional(),
|
|
6414
|
+
// `purchased`-specific (mínimo — transaction canônica leva detalhes)
|
|
6415
|
+
product_id: import_zod.z.string().optional()
|
|
6416
|
+
}).strict();
|
|
6417
|
+
transactionEventSchema = import_zod.z.object({
|
|
6418
|
+
type: import_zod.z.enum([
|
|
6419
|
+
"completed",
|
|
6420
|
+
"failed",
|
|
6421
|
+
"refunded",
|
|
6422
|
+
"renewed",
|
|
6423
|
+
"canceled",
|
|
6424
|
+
"expired"
|
|
6425
|
+
]),
|
|
6426
|
+
tx_id: import_zod.z.string().min(1),
|
|
6427
|
+
amount: import_zod.z.number().optional(),
|
|
6428
|
+
currency: import_zod.z.string().length(3).optional(),
|
|
6429
|
+
product_id: import_zod.z.string().optional(),
|
|
6430
|
+
subscription_id: import_zod.z.string().optional(),
|
|
6431
|
+
paywall_id: import_zod.z.string().optional(),
|
|
6432
|
+
variant_id: import_zod.z.string().optional(),
|
|
6433
|
+
reason: import_zod.z.string().optional()
|
|
6434
|
+
}).strict();
|
|
6435
|
+
onboardingEventSchema = import_zod.z.object({
|
|
6436
|
+
type: import_zod.z.enum(["step", "complete", "drop"]),
|
|
6437
|
+
step_index: import_zod.z.number().int().nonnegative().optional(),
|
|
6438
|
+
step_name: import_zod.z.string().optional(),
|
|
6439
|
+
variant_key: import_zod.z.string().optional(),
|
|
6440
|
+
time_on_prev_s: import_zod.z.number().nonnegative().optional()
|
|
6441
|
+
}).strict();
|
|
6442
|
+
notificationEventSchema = import_zod.z.object({
|
|
6443
|
+
type: import_zod.z.enum(["delivered", "displayed", "clicked", "dismissed"]),
|
|
6444
|
+
notification_id: import_zod.z.string().optional(),
|
|
6445
|
+
campaign_id: import_zod.z.string().optional(),
|
|
6446
|
+
variant_key: import_zod.z.string().nullable().optional(),
|
|
6447
|
+
message_id: import_zod.z.string().optional(),
|
|
6448
|
+
device_id: import_zod.z.string().optional(),
|
|
6449
|
+
push_platform: import_zod.z.enum(["ios", "android"]).optional(),
|
|
6450
|
+
timezone: import_zod.z.string().optional(),
|
|
6451
|
+
failure_reason: import_zod.z.string().optional(),
|
|
6452
|
+
app_user_id: import_zod.z.string().optional()
|
|
6453
|
+
}).strict();
|
|
6454
|
+
customEventSchema = import_zod.z.object({
|
|
6455
|
+
name: import_zod.z.string().min(1).regex(
|
|
6456
|
+
/^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/,
|
|
6457
|
+
"custom event name must be snake_case or $reserved"
|
|
6458
|
+
),
|
|
6459
|
+
props: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
6460
|
+
}).strict();
|
|
6461
|
+
EVENT_SCHEMAS = {
|
|
6462
|
+
lifecycle: lifecycleEventSchema,
|
|
6463
|
+
identify: identifyEventSchema,
|
|
6464
|
+
paywall: paywallEventSchema,
|
|
6465
|
+
transaction: transactionEventSchema,
|
|
6466
|
+
onboarding: onboardingEventSchema,
|
|
6467
|
+
notification: notificationEventSchema,
|
|
6468
|
+
custom: customEventSchema
|
|
6469
|
+
};
|
|
6470
|
+
}
|
|
6471
|
+
});
|
|
6472
|
+
|
|
6473
|
+
// src/core/events/eventFamilies.ts
|
|
6474
|
+
function isDeprecatedEvent(eventName) {
|
|
6475
|
+
return DEPRECATED_EVENT_NAMES.includes(eventName);
|
|
6476
|
+
}
|
|
6477
|
+
function isCanonicalFamily(name) {
|
|
6478
|
+
return CANONICAL_FAMILIES.includes(name);
|
|
6479
|
+
}
|
|
6480
|
+
function detectFamily(eventName) {
|
|
6481
|
+
if (isCanonicalFamily(eventName) && eventName !== "custom") {
|
|
6482
|
+
return eventName;
|
|
6483
|
+
}
|
|
6484
|
+
return "custom";
|
|
6485
|
+
}
|
|
6486
|
+
function validateEvent(eventName, properties) {
|
|
6487
|
+
const family = detectFamily(eventName);
|
|
6488
|
+
const schema = EVENT_SCHEMAS[family];
|
|
6489
|
+
const input = family === "custom" ? { name: eventName, ...properties ? { props: properties } : {} } : properties ?? {};
|
|
6490
|
+
const parsed = schema.safeParse(input);
|
|
6491
|
+
if (parsed.success) {
|
|
6492
|
+
return { ok: true, family, data: parsed.data };
|
|
6493
|
+
}
|
|
6494
|
+
return { ok: false, family, error: parsed.error };
|
|
6495
|
+
}
|
|
6496
|
+
function formatValidationError(error) {
|
|
6497
|
+
return error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
6498
|
+
}
|
|
6499
|
+
var CANONICAL_FAMILIES, DEPRECATED_EVENT_NAMES;
|
|
6500
|
+
var init_eventFamilies = __esm({
|
|
6501
|
+
"src/core/events/eventFamilies.ts"() {
|
|
6502
|
+
"use strict";
|
|
6503
|
+
init_schemas();
|
|
6504
|
+
CANONICAL_FAMILIES = [
|
|
6505
|
+
"lifecycle",
|
|
6506
|
+
"identify",
|
|
6507
|
+
"paywall",
|
|
6508
|
+
"transaction",
|
|
6509
|
+
"onboarding",
|
|
6510
|
+
"notification",
|
|
6511
|
+
"custom"
|
|
6512
|
+
];
|
|
6513
|
+
DEPRECATED_EVENT_NAMES = [
|
|
6514
|
+
"$paywall_purchased",
|
|
6515
|
+
"$paywall_product_selected",
|
|
6516
|
+
"$core_action",
|
|
6517
|
+
"$campaign_impression",
|
|
6518
|
+
"$app_open",
|
|
6519
|
+
"$app_background",
|
|
6520
|
+
"$app_foreground",
|
|
6521
|
+
"session.end"
|
|
6522
|
+
];
|
|
6523
|
+
}
|
|
6524
|
+
});
|
|
6525
|
+
|
|
6526
|
+
// src/core/PaywalloAnalytics.ts
|
|
6527
|
+
function isValidEventName(name) {
|
|
6528
|
+
if (name.startsWith("$")) return /^\$[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
|
|
6529
|
+
return /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
|
|
6530
|
+
}
|
|
6531
|
+
async function trackEvent(apiClient, state, eventName, options) {
|
|
6532
|
+
const distinctId = identityManager.getDistinctId();
|
|
6533
|
+
if (!distinctId) {
|
|
6534
|
+
console.error("[Paywallo:DROP] event dropped \u2014 no distinctId available yet", { eventName });
|
|
6535
|
+
return;
|
|
6536
|
+
}
|
|
6537
|
+
if (!isValidEventName(eventName)) {
|
|
6538
|
+
const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
|
|
6539
|
+
throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
|
|
6540
|
+
}
|
|
6541
|
+
if (state.config?.debug && eventName.startsWith("$purchase")) console.log(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
6542
|
+
const sessionId = sessionManager.getSessionId();
|
|
6543
|
+
const family = detectFamily(eventName);
|
|
6544
|
+
const isCustomFamily = family === "custom";
|
|
6545
|
+
const identityProps = isCustomFamily ? identityManager.getProperties() : {};
|
|
6546
|
+
const sessionProp = isCustomFamily && sessionId ? { sessionId } : {};
|
|
6547
|
+
await apiClient.trackEvent(
|
|
6548
|
+
eventName,
|
|
6549
|
+
distinctId,
|
|
6550
|
+
{ ...identityProps, ...options?.properties, ...sessionProp },
|
|
6551
|
+
options?.timestamp,
|
|
6552
|
+
options?.priority ? { priority: options.priority } : void 0
|
|
6553
|
+
);
|
|
6554
|
+
}
|
|
6555
|
+
async function trackOnboardingStep(apiClient, state, index, name) {
|
|
6556
|
+
const distinctId = identityManager.getDistinctId();
|
|
6557
|
+
if (!distinctId) return;
|
|
6558
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
6559
|
+
const msg = `Invalid stepIndex: "${index}". Must be a non-negative integer.`;
|
|
6560
|
+
throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_STEP_INDEX, msg);
|
|
6561
|
+
}
|
|
6562
|
+
const now = Date.now();
|
|
6563
|
+
const timeOnPreviousStep = state.lastOnboardingStepTimestamp !== null ? Math.round((now - state.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
6564
|
+
state.lastOnboardingStepTimestamp = now;
|
|
6565
|
+
await apiClient.trackEvent("$onboarding_step", distinctId, { stepIndex: index, stepName: name, timeOnPreviousStep });
|
|
6566
|
+
}
|
|
6567
|
+
function validateCoreAction(actionName) {
|
|
6568
|
+
if (!actionName || typeof actionName !== "string") {
|
|
6569
|
+
const msg = `Invalid actionName: "${actionName}". Must be a non-empty string.`;
|
|
6570
|
+
throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_ACTION_NAME, msg);
|
|
6571
|
+
}
|
|
6572
|
+
}
|
|
6573
|
+
var init_PaywalloAnalytics = __esm({
|
|
6574
|
+
"src/core/PaywalloAnalytics.ts"() {
|
|
6575
|
+
"use strict";
|
|
6576
|
+
init_analytics();
|
|
6577
|
+
init_identity();
|
|
6578
|
+
init_session();
|
|
6579
|
+
init_ClientError();
|
|
6580
|
+
init_eventFamilies();
|
|
6581
|
+
}
|
|
6582
|
+
});
|
|
6583
|
+
|
|
6584
|
+
// src/core/PaywalloFlags.ts
|
|
6585
|
+
async function getVariantCached(apiClient, flagKey, defaultValue) {
|
|
6586
|
+
const distinctId = identityManager.getDistinctId();
|
|
6587
|
+
const result = await apiClient.getVariantFromCache(flagKey, distinctId);
|
|
6588
|
+
if (result) return result;
|
|
6589
|
+
void apiClient.getVariant(flagKey, distinctId).catch(() => {
|
|
6590
|
+
});
|
|
6591
|
+
return { variant: defaultValue ?? null, payload: void 0 };
|
|
6592
|
+
}
|
|
6593
|
+
async function getVariant(apiClient, state, flagKey) {
|
|
6594
|
+
try {
|
|
6595
|
+
const distinctId = identityManager.getDistinctId();
|
|
6596
|
+
if (!distinctId) {
|
|
6597
|
+
if (state.config?.debug) console.log(`[Paywallo FLAG] ${flagKey} \u2192 null (no distinctId)`);
|
|
6598
|
+
return { variant: null };
|
|
6599
|
+
}
|
|
6600
|
+
const result = await apiClient.getVariant(flagKey, distinctId);
|
|
6601
|
+
if (state.config?.debug) console.log(`[Paywallo FLAG] ${flagKey} \u2192`, result.variant);
|
|
6602
|
+
return result;
|
|
6603
|
+
} catch (error) {
|
|
6604
|
+
if (state.config?.debug) console.log(`[Paywallo FLAG] ${flagKey} \u2192 error`, error);
|
|
6605
|
+
if (state.apiClient) void state.apiClient.reportError("GET_VARIANT_FAILED", error instanceof Error ? error.message : String(error));
|
|
6606
|
+
return { variant: null };
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
function evaluateFlags(apiClient, keys) {
|
|
6610
|
+
return apiClient.evaluateFlags(keys, identityManager.getDistinctId());
|
|
6611
|
+
}
|
|
6612
|
+
async function getConditionalFlag(apiClient, state, flagKey, context) {
|
|
6613
|
+
try {
|
|
6614
|
+
const distinctId = identityManager.getDistinctId();
|
|
6615
|
+
if (!distinctId) return false;
|
|
6616
|
+
const result = await apiClient.getConditionalFlag(flagKey, { distinctId, ...context });
|
|
6617
|
+
return result.value;
|
|
6618
|
+
} catch (error) {
|
|
6619
|
+
if (state.apiClient) void state.apiClient.reportError("GET_CONDITIONAL_FLAG_FAILED", error instanceof Error ? error.message : String(error));
|
|
6124
6620
|
return false;
|
|
6125
6621
|
}
|
|
6126
6622
|
}
|
|
@@ -6346,49 +6842,49 @@ var init_SubscriptionCache = __esm({
|
|
|
6346
6842
|
await this.storage.remove(keyFor(distinctId));
|
|
6347
6843
|
return null;
|
|
6348
6844
|
}
|
|
6349
|
-
const
|
|
6350
|
-
if (
|
|
6351
|
-
|
|
6845
|
+
const cached2 = parsed;
|
|
6846
|
+
if (cached2.data.subscription?.expiresAt) {
|
|
6847
|
+
cached2.data.subscription.expiresAt = new Date(cached2.data.subscription.expiresAt);
|
|
6352
6848
|
}
|
|
6353
|
-
if (
|
|
6354
|
-
|
|
6355
|
-
|
|
6849
|
+
if (cached2.data.subscription?.originalPurchaseDate) {
|
|
6850
|
+
cached2.data.subscription.originalPurchaseDate = new Date(
|
|
6851
|
+
cached2.data.subscription.originalPurchaseDate
|
|
6356
6852
|
);
|
|
6357
6853
|
}
|
|
6358
|
-
if (
|
|
6359
|
-
|
|
6360
|
-
|
|
6854
|
+
if (cached2.data.subscription?.latestPurchaseDate) {
|
|
6855
|
+
cached2.data.subscription.latestPurchaseDate = new Date(
|
|
6856
|
+
cached2.data.subscription.latestPurchaseDate
|
|
6361
6857
|
);
|
|
6362
6858
|
}
|
|
6363
|
-
if (
|
|
6364
|
-
|
|
6365
|
-
|
|
6859
|
+
if (cached2.data.subscription?.cancellationDate) {
|
|
6860
|
+
cached2.data.subscription.cancellationDate = new Date(
|
|
6861
|
+
cached2.data.subscription.cancellationDate
|
|
6366
6862
|
);
|
|
6367
6863
|
}
|
|
6368
|
-
if (
|
|
6369
|
-
|
|
6370
|
-
|
|
6864
|
+
if (cached2.data.subscription?.gracePeriodExpiresAt) {
|
|
6865
|
+
cached2.data.subscription.gracePeriodExpiresAt = new Date(
|
|
6866
|
+
cached2.data.subscription.gracePeriodExpiresAt
|
|
6371
6867
|
);
|
|
6372
6868
|
}
|
|
6373
|
-
|
|
6374
|
-
if (!
|
|
6375
|
-
this.memoryCache.set(distinctId,
|
|
6869
|
+
cached2.isStale = this.isExpired(cached2);
|
|
6870
|
+
if (!cached2.isStale) {
|
|
6871
|
+
this.memoryCache.set(distinctId, cached2);
|
|
6376
6872
|
}
|
|
6377
|
-
return
|
|
6873
|
+
return cached2;
|
|
6378
6874
|
} catch {
|
|
6379
6875
|
return null;
|
|
6380
6876
|
}
|
|
6381
6877
|
}
|
|
6382
6878
|
async set(distinctId, data) {
|
|
6383
6879
|
if (!distinctId) return;
|
|
6384
|
-
const
|
|
6880
|
+
const cached2 = {
|
|
6385
6881
|
data,
|
|
6386
6882
|
cachedAt: Date.now(),
|
|
6387
6883
|
isStale: false
|
|
6388
6884
|
};
|
|
6389
|
-
this.memoryCache.set(distinctId,
|
|
6885
|
+
this.memoryCache.set(distinctId, cached2);
|
|
6390
6886
|
try {
|
|
6391
|
-
await this.storage.set(keyFor(distinctId), JSON.stringify(
|
|
6887
|
+
await this.storage.set(keyFor(distinctId), JSON.stringify(cached2));
|
|
6392
6888
|
await this.addToIndex(distinctId);
|
|
6393
6889
|
} catch {
|
|
6394
6890
|
}
|
|
@@ -6432,8 +6928,8 @@ var init_SubscriptionCache = __esm({
|
|
|
6432
6928
|
...allKeys.map((k) => this.storage.remove(keyFor(k)))
|
|
6433
6929
|
]);
|
|
6434
6930
|
}
|
|
6435
|
-
isExpired(
|
|
6436
|
-
return Date.now() -
|
|
6931
|
+
isExpired(cached2) {
|
|
6932
|
+
return Date.now() - cached2.cachedAt > this.ttl;
|
|
6437
6933
|
}
|
|
6438
6934
|
setTTL(ttl) {
|
|
6439
6935
|
this.ttl = ttl;
|
|
@@ -6489,9 +6985,9 @@ var init_SubscriptionManager = __esm({
|
|
|
6489
6985
|
return this.getEmptyStatus();
|
|
6490
6986
|
}
|
|
6491
6987
|
if (!forceRefresh) {
|
|
6492
|
-
const
|
|
6493
|
-
if (
|
|
6494
|
-
return
|
|
6988
|
+
const cached2 = await this.cache.get(this.cacheKey());
|
|
6989
|
+
if (cached2 && !cached2.isStale) {
|
|
6990
|
+
return cached2.data;
|
|
6495
6991
|
}
|
|
6496
6992
|
}
|
|
6497
6993
|
try {
|
|
@@ -6501,9 +6997,9 @@ var init_SubscriptionManager = __esm({
|
|
|
6501
6997
|
return status;
|
|
6502
6998
|
} catch (error) {
|
|
6503
6999
|
this.log("Failed to fetch subscription status", error);
|
|
6504
|
-
const
|
|
6505
|
-
if (
|
|
6506
|
-
return
|
|
7000
|
+
const cached2 = await this.cache.get(this.cacheKey());
|
|
7001
|
+
if (cached2) {
|
|
7002
|
+
return cached2.data;
|
|
6507
7003
|
}
|
|
6508
7004
|
return this.getEmptyStatus();
|
|
6509
7005
|
}
|
|
@@ -6816,262 +7312,105 @@ async function getVariant2(deps, flagKey, distinctId) {
|
|
|
6816
7312
|
return v;
|
|
6817
7313
|
}
|
|
6818
7314
|
if (!res.ok) {
|
|
6819
|
-
const stale = deps.cache.getStaleVariant(key);
|
|
6820
|
-
return stale !== void 0 ? stale : { variant: null };
|
|
6821
|
-
}
|
|
6822
|
-
deps.cache.setVariant(key, res.data);
|
|
6823
|
-
await writeFlagToStorage(flagKey, distinctId, res.data);
|
|
6824
|
-
return res.data;
|
|
6825
|
-
} catch {
|
|
6826
|
-
const stale = deps.cache.getStaleVariant(key);
|
|
6827
|
-
return stale !== void 0 ? stale : { variant: null };
|
|
6828
|
-
}
|
|
6829
|
-
}
|
|
6830
|
-
async function evaluateFlags2(deps, keys, distinctId) {
|
|
6831
|
-
const query = keys.map(encodeURIComponent).join(",");
|
|
6832
|
-
try {
|
|
6833
|
-
const res = await deps.httpClient.get(`/sdk/flags/evaluate?keys=${query}`, {
|
|
6834
|
-
headers: { "X-App-Key": deps.appKey, "x-distinct-id": distinctId }
|
|
6835
|
-
});
|
|
6836
|
-
if (!res.ok || typeof res.data !== "object" || res.data === null || Array.isArray(res.data)) return {};
|
|
6837
|
-
const record = res.data;
|
|
6838
|
-
const result = {};
|
|
6839
|
-
for (const key of Object.keys(record)) {
|
|
6840
|
-
const value = record[key];
|
|
6841
|
-
const variant = typeof value === "string" ? value : null;
|
|
6842
|
-
result[key] = variant;
|
|
6843
|
-
const flagVariant = { variant };
|
|
6844
|
-
deps.cache.setVariant(`${key}:${distinctId}`, flagVariant);
|
|
6845
|
-
await writeFlagToStorage(key, distinctId, flagVariant);
|
|
6846
|
-
}
|
|
6847
|
-
return result;
|
|
6848
|
-
} catch {
|
|
6849
|
-
return {};
|
|
6850
|
-
}
|
|
6851
|
-
}
|
|
6852
|
-
async function getConditionalFlag2(deps, flagKey, context) {
|
|
6853
|
-
try {
|
|
6854
|
-
const url = buildConditionalFlagUrl(deps.baseUrl, flagKey, context);
|
|
6855
|
-
const response = await deps.get(url);
|
|
6856
|
-
if (response.status === 404 || !response.ok) return { value: false, flagKey };
|
|
6857
|
-
return { value: response.data.value, flagKey };
|
|
6858
|
-
} catch {
|
|
6859
|
-
return { value: false, flagKey };
|
|
6860
|
-
}
|
|
6861
|
-
}
|
|
6862
|
-
async function getVariantFromCache(deps, flagKey, distinctId) {
|
|
6863
|
-
const key = `${flagKey}:${distinctId}`;
|
|
6864
|
-
const hit = deps.cache.getVariant(key);
|
|
6865
|
-
if (hit !== void 0) return hit;
|
|
6866
|
-
const persisted = await readFlagFromStorage(flagKey, distinctId);
|
|
6867
|
-
if (persisted !== null) {
|
|
6868
|
-
deps.cache.setVariant(key, persisted);
|
|
6869
|
-
return persisted;
|
|
6870
|
-
}
|
|
6871
|
-
return null;
|
|
6872
|
-
}
|
|
6873
|
-
var init_ApiClientFlags = __esm({
|
|
6874
|
-
"src/core/ApiClientFlags.ts"() {
|
|
6875
|
-
"use strict";
|
|
6876
|
-
init_apiUrlUtils();
|
|
6877
|
-
init_FlagStorage();
|
|
6878
|
-
}
|
|
6879
|
-
});
|
|
6880
|
-
|
|
6881
|
-
// src/core/ApiClientQueue.ts
|
|
6882
|
-
async function postWithQueue(deps, url, payload, label, priority) {
|
|
6883
|
-
if (deps.isOfflineQueueEnabled() && !networkMonitor.isOnline()) {
|
|
6884
|
-
await offlineQueue.enqueue(
|
|
6885
|
-
"POST",
|
|
6886
|
-
url,
|
|
6887
|
-
payload,
|
|
6888
|
-
{ "X-App-Key": deps.getAppKey() },
|
|
6889
|
-
void 0,
|
|
6890
|
-
priority
|
|
6891
|
-
);
|
|
6892
|
-
if (deps.isDebug()) console.log("[Paywallo:ApiClient] Queued for offline:", label, priority ?? "normal");
|
|
6893
|
-
return;
|
|
6894
|
-
}
|
|
6895
|
-
try {
|
|
6896
|
-
await deps.post(url, payload);
|
|
6897
|
-
} catch (error) {
|
|
6898
|
-
if (deps.isDebug()) console.log("[Paywallo:ApiClient] Request failed:", label, error);
|
|
6899
|
-
if (deps.isOfflineQueueEnabled()) {
|
|
6900
|
-
await offlineQueue.enqueue(
|
|
6901
|
-
"POST",
|
|
6902
|
-
url,
|
|
6903
|
-
payload,
|
|
6904
|
-
{ "X-App-Key": deps.getAppKey() },
|
|
6905
|
-
void 0,
|
|
6906
|
-
priority
|
|
6907
|
-
);
|
|
6908
|
-
return;
|
|
6909
|
-
}
|
|
6910
|
-
throw error;
|
|
6911
|
-
}
|
|
6912
|
-
}
|
|
6913
|
-
var init_ApiClientQueue = __esm({
|
|
6914
|
-
"src/core/ApiClientQueue.ts"() {
|
|
6915
|
-
"use strict";
|
|
6916
|
-
init_network();
|
|
6917
|
-
init_queue();
|
|
6918
|
-
}
|
|
6919
|
-
});
|
|
6920
|
-
|
|
6921
|
-
// src/core/events/schemas.ts
|
|
6922
|
-
var import_zod, lifecycleEventSchema, identifyEventSchema, paywallEventSchema, transactionEventSchema, onboardingEventSchema, notificationEventSchema, customEventSchema, EVENT_SCHEMAS;
|
|
6923
|
-
var init_schemas = __esm({
|
|
6924
|
-
"src/core/events/schemas.ts"() {
|
|
6925
|
-
"use strict";
|
|
6926
|
-
import_zod = require("zod");
|
|
6927
|
-
lifecycleEventSchema = import_zod.z.object({
|
|
6928
|
-
type: import_zod.z.enum([
|
|
6929
|
-
"install",
|
|
6930
|
-
"cold_start",
|
|
6931
|
-
"foreground",
|
|
6932
|
-
"background",
|
|
6933
|
-
"session_start",
|
|
6934
|
-
"session_end"
|
|
6935
|
-
]),
|
|
6936
|
-
session_id: import_zod.z.string().optional(),
|
|
6937
|
-
duration_s: import_zod.z.number().nonnegative().optional(),
|
|
6938
|
-
first_ever: import_zod.z.boolean().optional(),
|
|
6939
|
-
// Contexto leve transportado em lifecycle (útil pra cold_start/install)
|
|
6940
|
-
app_version: import_zod.z.string().optional(),
|
|
6941
|
-
device_type: import_zod.z.enum(["ios", "android"]).optional(),
|
|
6942
|
-
os_version: import_zod.z.string().optional(),
|
|
6943
|
-
// Timestamps opcionais — o EventBatcher injeta `timestamp` no envelope
|
|
6944
|
-
started_at: import_zod.z.string().optional(),
|
|
6945
|
-
ended_at: import_zod.z.string().optional()
|
|
6946
|
-
}).strict();
|
|
6947
|
-
identifyEventSchema = import_zod.z.object({
|
|
6948
|
-
distinct_id: import_zod.z.string().min(1),
|
|
6949
|
-
email: import_zod.z.email().optional(),
|
|
6950
|
-
traits: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
6951
|
-
attribution: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
6952
|
-
device: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
6953
|
-
}).strict();
|
|
6954
|
-
paywallEventSchema = import_zod.z.object({
|
|
6955
|
-
type: import_zod.z.enum(["viewed", "closed", "purchased"]),
|
|
6956
|
-
paywall_id: import_zod.z.string().min(1),
|
|
6957
|
-
placement: import_zod.z.string().optional(),
|
|
6958
|
-
variant_id: import_zod.z.string().optional(),
|
|
6959
|
-
variant_key: import_zod.z.string().optional(),
|
|
6960
|
-
campaign_id: import_zod.z.string().optional(),
|
|
6961
|
-
// `closed`-specific
|
|
6962
|
-
closed_at: import_zod.z.string().optional(),
|
|
6963
|
-
duration_s: import_zod.z.number().nonnegative().optional(),
|
|
6964
|
-
close_reason: import_zod.z.enum(["dismiss", "cta", "purchase", "error", "timeout"]).optional(),
|
|
6965
|
-
scroll_depth: import_zod.z.number().min(0).max(1).optional(),
|
|
6966
|
-
// `purchased`-specific (mínimo — transaction canônica leva detalhes)
|
|
6967
|
-
product_id: import_zod.z.string().optional()
|
|
6968
|
-
}).strict();
|
|
6969
|
-
transactionEventSchema = import_zod.z.object({
|
|
6970
|
-
type: import_zod.z.enum([
|
|
6971
|
-
"completed",
|
|
6972
|
-
"failed",
|
|
6973
|
-
"refunded",
|
|
6974
|
-
"renewed",
|
|
6975
|
-
"canceled",
|
|
6976
|
-
"expired"
|
|
6977
|
-
]),
|
|
6978
|
-
tx_id: import_zod.z.string().min(1),
|
|
6979
|
-
amount: import_zod.z.number().optional(),
|
|
6980
|
-
currency: import_zod.z.string().length(3).optional(),
|
|
6981
|
-
product_id: import_zod.z.string().optional(),
|
|
6982
|
-
subscription_id: import_zod.z.string().optional(),
|
|
6983
|
-
paywall_id: import_zod.z.string().optional(),
|
|
6984
|
-
variant_id: import_zod.z.string().optional(),
|
|
6985
|
-
reason: import_zod.z.string().optional()
|
|
6986
|
-
}).strict();
|
|
6987
|
-
onboardingEventSchema = import_zod.z.object({
|
|
6988
|
-
type: import_zod.z.enum(["step", "complete", "drop"]),
|
|
6989
|
-
step_index: import_zod.z.number().int().nonnegative().optional(),
|
|
6990
|
-
step_name: import_zod.z.string().optional(),
|
|
6991
|
-
variant_key: import_zod.z.string().optional(),
|
|
6992
|
-
time_on_prev_s: import_zod.z.number().nonnegative().optional()
|
|
6993
|
-
}).strict();
|
|
6994
|
-
notificationEventSchema = import_zod.z.object({
|
|
6995
|
-
type: import_zod.z.enum(["delivered", "displayed", "clicked", "dismissed"]),
|
|
6996
|
-
notification_id: import_zod.z.string().optional(),
|
|
6997
|
-
campaign_id: import_zod.z.string().optional(),
|
|
6998
|
-
variant_key: import_zod.z.string().nullable().optional(),
|
|
6999
|
-
message_id: import_zod.z.string().optional(),
|
|
7000
|
-
device_id: import_zod.z.string().optional(),
|
|
7001
|
-
push_platform: import_zod.z.enum(["ios", "android"]).optional(),
|
|
7002
|
-
timezone: import_zod.z.string().optional(),
|
|
7003
|
-
failure_reason: import_zod.z.string().optional(),
|
|
7004
|
-
app_user_id: import_zod.z.string().optional()
|
|
7005
|
-
}).strict();
|
|
7006
|
-
customEventSchema = import_zod.z.object({
|
|
7007
|
-
name: import_zod.z.string().min(1).regex(
|
|
7008
|
-
/^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/,
|
|
7009
|
-
"custom event name must be snake_case or $reserved"
|
|
7010
|
-
),
|
|
7011
|
-
props: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
7012
|
-
}).strict();
|
|
7013
|
-
EVENT_SCHEMAS = {
|
|
7014
|
-
lifecycle: lifecycleEventSchema,
|
|
7015
|
-
identify: identifyEventSchema,
|
|
7016
|
-
paywall: paywallEventSchema,
|
|
7017
|
-
transaction: transactionEventSchema,
|
|
7018
|
-
onboarding: onboardingEventSchema,
|
|
7019
|
-
notification: notificationEventSchema,
|
|
7020
|
-
custom: customEventSchema
|
|
7021
|
-
};
|
|
7315
|
+
const stale = deps.cache.getStaleVariant(key);
|
|
7316
|
+
return stale !== void 0 ? stale : { variant: null };
|
|
7317
|
+
}
|
|
7318
|
+
deps.cache.setVariant(key, res.data);
|
|
7319
|
+
await writeFlagToStorage(flagKey, distinctId, res.data);
|
|
7320
|
+
return res.data;
|
|
7321
|
+
} catch {
|
|
7322
|
+
const stale = deps.cache.getStaleVariant(key);
|
|
7323
|
+
return stale !== void 0 ? stale : { variant: null };
|
|
7022
7324
|
}
|
|
7023
|
-
});
|
|
7024
|
-
|
|
7025
|
-
// src/core/events/eventFamilies.ts
|
|
7026
|
-
function isDeprecatedEvent(eventName) {
|
|
7027
|
-
return DEPRECATED_EVENT_NAMES.includes(eventName);
|
|
7028
7325
|
}
|
|
7029
|
-
function
|
|
7030
|
-
|
|
7326
|
+
async function evaluateFlags2(deps, keys, distinctId) {
|
|
7327
|
+
const query = keys.map(encodeURIComponent).join(",");
|
|
7328
|
+
try {
|
|
7329
|
+
const res = await deps.httpClient.get(`/sdk/flags/evaluate?keys=${query}`, {
|
|
7330
|
+
headers: { "X-App-Key": deps.appKey, "x-distinct-id": distinctId }
|
|
7331
|
+
});
|
|
7332
|
+
if (!res.ok || typeof res.data !== "object" || res.data === null || Array.isArray(res.data)) return {};
|
|
7333
|
+
const record = res.data;
|
|
7334
|
+
const result = {};
|
|
7335
|
+
for (const key of Object.keys(record)) {
|
|
7336
|
+
const value = record[key];
|
|
7337
|
+
const variant = typeof value === "string" ? value : null;
|
|
7338
|
+
result[key] = variant;
|
|
7339
|
+
const flagVariant = { variant };
|
|
7340
|
+
deps.cache.setVariant(`${key}:${distinctId}`, flagVariant);
|
|
7341
|
+
await writeFlagToStorage(key, distinctId, flagVariant);
|
|
7342
|
+
}
|
|
7343
|
+
return result;
|
|
7344
|
+
} catch {
|
|
7345
|
+
return {};
|
|
7346
|
+
}
|
|
7031
7347
|
}
|
|
7032
|
-
function
|
|
7033
|
-
|
|
7034
|
-
|
|
7348
|
+
async function getConditionalFlag2(deps, flagKey, context) {
|
|
7349
|
+
try {
|
|
7350
|
+
const url = buildConditionalFlagUrl(deps.baseUrl, flagKey, context);
|
|
7351
|
+
const response = await deps.get(url);
|
|
7352
|
+
if (response.status === 404 || !response.ok) return { value: false, flagKey };
|
|
7353
|
+
return { value: response.data.value, flagKey };
|
|
7354
|
+
} catch {
|
|
7355
|
+
return { value: false, flagKey };
|
|
7035
7356
|
}
|
|
7036
|
-
return "custom";
|
|
7037
7357
|
}
|
|
7038
|
-
function
|
|
7039
|
-
const
|
|
7040
|
-
const
|
|
7041
|
-
|
|
7042
|
-
const
|
|
7043
|
-
if (
|
|
7044
|
-
|
|
7358
|
+
async function getVariantFromCache(deps, flagKey, distinctId) {
|
|
7359
|
+
const key = `${flagKey}:${distinctId}`;
|
|
7360
|
+
const hit = deps.cache.getVariant(key);
|
|
7361
|
+
if (hit !== void 0) return hit;
|
|
7362
|
+
const persisted = await readFlagFromStorage(flagKey, distinctId);
|
|
7363
|
+
if (persisted !== null) {
|
|
7364
|
+
deps.cache.setVariant(key, persisted);
|
|
7365
|
+
return persisted;
|
|
7045
7366
|
}
|
|
7046
|
-
return
|
|
7367
|
+
return null;
|
|
7047
7368
|
}
|
|
7048
|
-
|
|
7049
|
-
|
|
7369
|
+
var init_ApiClientFlags = __esm({
|
|
7370
|
+
"src/core/ApiClientFlags.ts"() {
|
|
7371
|
+
"use strict";
|
|
7372
|
+
init_apiUrlUtils();
|
|
7373
|
+
init_FlagStorage();
|
|
7374
|
+
}
|
|
7375
|
+
});
|
|
7376
|
+
|
|
7377
|
+
// src/core/ApiClientQueue.ts
|
|
7378
|
+
async function postWithQueue(deps, url, payload, label, priority) {
|
|
7379
|
+
if (deps.isOfflineQueueEnabled() && !networkMonitor.isOnline()) {
|
|
7380
|
+
await offlineQueue.enqueue(
|
|
7381
|
+
"POST",
|
|
7382
|
+
url,
|
|
7383
|
+
payload,
|
|
7384
|
+
{ "X-App-Key": deps.getAppKey() },
|
|
7385
|
+
void 0,
|
|
7386
|
+
priority
|
|
7387
|
+
);
|
|
7388
|
+
if (deps.isDebug()) console.log("[Paywallo:ApiClient] Queued for offline:", label, priority ?? "normal");
|
|
7389
|
+
return;
|
|
7390
|
+
}
|
|
7391
|
+
try {
|
|
7392
|
+
await deps.post(url, payload);
|
|
7393
|
+
} catch (error) {
|
|
7394
|
+
if (deps.isDebug()) console.log("[Paywallo:ApiClient] Request failed:", label, error);
|
|
7395
|
+
if (deps.isOfflineQueueEnabled()) {
|
|
7396
|
+
await offlineQueue.enqueue(
|
|
7397
|
+
"POST",
|
|
7398
|
+
url,
|
|
7399
|
+
payload,
|
|
7400
|
+
{ "X-App-Key": deps.getAppKey() },
|
|
7401
|
+
void 0,
|
|
7402
|
+
priority
|
|
7403
|
+
);
|
|
7404
|
+
return;
|
|
7405
|
+
}
|
|
7406
|
+
throw error;
|
|
7407
|
+
}
|
|
7050
7408
|
}
|
|
7051
|
-
var
|
|
7052
|
-
|
|
7053
|
-
"src/core/events/eventFamilies.ts"() {
|
|
7409
|
+
var init_ApiClientQueue = __esm({
|
|
7410
|
+
"src/core/ApiClientQueue.ts"() {
|
|
7054
7411
|
"use strict";
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
"lifecycle",
|
|
7058
|
-
"identify",
|
|
7059
|
-
"paywall",
|
|
7060
|
-
"transaction",
|
|
7061
|
-
"onboarding",
|
|
7062
|
-
"notification",
|
|
7063
|
-
"custom"
|
|
7064
|
-
];
|
|
7065
|
-
DEPRECATED_EVENT_NAMES = [
|
|
7066
|
-
"$paywall_purchased",
|
|
7067
|
-
"$paywall_product_selected",
|
|
7068
|
-
"$core_action",
|
|
7069
|
-
"$campaign_impression",
|
|
7070
|
-
"$app_open",
|
|
7071
|
-
"$app_background",
|
|
7072
|
-
"$app_foreground",
|
|
7073
|
-
"session.end"
|
|
7074
|
-
];
|
|
7412
|
+
init_network();
|
|
7413
|
+
init_queue();
|
|
7075
7414
|
}
|
|
7076
7415
|
});
|
|
7077
7416
|
|
|
@@ -7098,10 +7437,13 @@ function buildV2Envelope(events, providerContext) {
|
|
|
7098
7437
|
};
|
|
7099
7438
|
});
|
|
7100
7439
|
if (context.sdk_version === void 0) context.sdk_version = SDK_VERSION;
|
|
7101
|
-
if (context.platform === void 0) context.platform =
|
|
7440
|
+
if (context.platform === void 0) context.platform = import_react_native23.Platform.OS;
|
|
7102
7441
|
if (context.distinct_id === void 0 && events.length > 0) {
|
|
7103
7442
|
context.distinct_id = events[0].distinctId;
|
|
7104
7443
|
}
|
|
7444
|
+
if (!context.distinct_id || context.distinct_id.length === 0) {
|
|
7445
|
+
console.error("[Paywallo:ENVELOPE] distinct_id is empty after resolution \u2014 envelope will fail schema", { providerContext, eventCount: events.length, firstEventName: events[0]?.eventName });
|
|
7446
|
+
}
|
|
7105
7447
|
return { context, events: v2Events };
|
|
7106
7448
|
}
|
|
7107
7449
|
function resolveProviderContext(provider) {
|
|
@@ -7135,11 +7477,11 @@ function splitPayloadAndContext(properties) {
|
|
|
7135
7477
|
}
|
|
7136
7478
|
return { payload, promoted };
|
|
7137
7479
|
}
|
|
7138
|
-
var
|
|
7480
|
+
var import_react_native23, import_zod2, v2EventSchema, v2ContextSchema, v2EnvelopeSchema, CONTEXT_KEY_ALIASES;
|
|
7139
7481
|
var init_eventEnvelopeV2 = __esm({
|
|
7140
7482
|
"src/core/eventEnvelopeV2.ts"() {
|
|
7141
7483
|
"use strict";
|
|
7142
|
-
|
|
7484
|
+
import_react_native23 = require("react-native");
|
|
7143
7485
|
import_zod2 = require("zod");
|
|
7144
7486
|
init_uuid();
|
|
7145
7487
|
init_eventFamilies();
|
|
@@ -7155,12 +7497,18 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7155
7497
|
session_id: import_zod2.z.string().optional(),
|
|
7156
7498
|
device_id: import_zod2.z.string().optional(),
|
|
7157
7499
|
app_version: import_zod2.z.string().optional(),
|
|
7500
|
+
app_build: import_zod2.z.string().optional(),
|
|
7501
|
+
bundle_id: import_zod2.z.string().optional(),
|
|
7158
7502
|
sdk_version: import_zod2.z.string().optional(),
|
|
7159
7503
|
platform: import_zod2.z.string().optional(),
|
|
7160
7504
|
os_version: import_zod2.z.string().optional(),
|
|
7161
7505
|
device_model: import_zod2.z.string().optional(),
|
|
7162
7506
|
timezone: import_zod2.z.string().optional(),
|
|
7163
7507
|
locale: import_zod2.z.string().optional(),
|
|
7508
|
+
carrier: import_zod2.z.string().optional(),
|
|
7509
|
+
screen_width: import_zod2.z.number().optional(),
|
|
7510
|
+
screen_height: import_zod2.z.number().optional(),
|
|
7511
|
+
screen_density: import_zod2.z.number().optional(),
|
|
7164
7512
|
attribution: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional(),
|
|
7165
7513
|
ids: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional()
|
|
7166
7514
|
});
|
|
@@ -7173,12 +7521,21 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7173
7521
|
session_id: ["session_id", "sessionId"],
|
|
7174
7522
|
device_id: ["device_id", "deviceId"],
|
|
7175
7523
|
app_version: ["app_version", "appVersion"],
|
|
7524
|
+
// F2.2 — alias só snake_case canônico: campos vêm do context provider, não
|
|
7525
|
+
// de properties de evento. Evita promover (e deletar) chaves do payload do
|
|
7526
|
+
// $app_installed que o server lê (screenWidth etc.).
|
|
7527
|
+
app_build: ["app_build"],
|
|
7528
|
+
bundle_id: ["bundle_id"],
|
|
7176
7529
|
sdk_version: ["sdk_version", "sdkVersion"],
|
|
7177
7530
|
platform: ["platform"],
|
|
7178
7531
|
os_version: ["os_version", "osVersion", "systemVersion"],
|
|
7179
7532
|
device_model: ["device_model", "deviceModel", "model"],
|
|
7180
7533
|
timezone: ["timezone", "timeZone"],
|
|
7181
7534
|
locale: ["locale"],
|
|
7535
|
+
carrier: ["carrier_ctx"],
|
|
7536
|
+
screen_width: ["screen_width"],
|
|
7537
|
+
screen_height: ["screen_height"],
|
|
7538
|
+
screen_density: ["screen_density"],
|
|
7182
7539
|
attribution: ["attribution"],
|
|
7183
7540
|
ids: ["ids"]
|
|
7184
7541
|
};
|
|
@@ -7194,11 +7551,11 @@ var init_events = __esm({
|
|
|
7194
7551
|
});
|
|
7195
7552
|
|
|
7196
7553
|
// src/core/EventBatcher.ts
|
|
7197
|
-
var
|
|
7554
|
+
var import_react_native24, BATCH_MAX_SIZE, BATCH_FLUSH_MS, EVENT_NAME_REGEX, V2_BATCH_ENDPOINT, EventBatcher;
|
|
7198
7555
|
var init_EventBatcher = __esm({
|
|
7199
7556
|
"src/core/EventBatcher.ts"() {
|
|
7200
7557
|
"use strict";
|
|
7201
|
-
|
|
7558
|
+
import_react_native24 = require("react-native");
|
|
7202
7559
|
init_eventEnvelopeV2();
|
|
7203
7560
|
init_events();
|
|
7204
7561
|
BATCH_MAX_SIZE = 25;
|
|
@@ -7247,7 +7604,7 @@ var init_EventBatcher = __esm({
|
|
|
7247
7604
|
const event = {
|
|
7248
7605
|
eventName,
|
|
7249
7606
|
distinctId,
|
|
7250
|
-
properties: { ...properties, platform:
|
|
7607
|
+
properties: { ...properties, platform: import_react_native24.Platform.OS },
|
|
7251
7608
|
timestamp: timestamp ?? Date.now(),
|
|
7252
7609
|
environment: environment.toLowerCase()
|
|
7253
7610
|
};
|
|
@@ -7305,8 +7662,8 @@ var init_EventBatcher = __esm({
|
|
|
7305
7662
|
for (const event of drained) {
|
|
7306
7663
|
try {
|
|
7307
7664
|
await this.postBatch([event], `event_critical:${event.eventName}`, "critical");
|
|
7308
|
-
} catch {
|
|
7309
|
-
|
|
7665
|
+
} catch (err) {
|
|
7666
|
+
console.error("[Paywallo:CRITICAL] critical event post failed", { eventName: event.eventName, error: err instanceof Error ? err.message : String(err) });
|
|
7310
7667
|
}
|
|
7311
7668
|
}
|
|
7312
7669
|
}
|
|
@@ -7319,8 +7676,8 @@ var init_EventBatcher = __esm({
|
|
|
7319
7676
|
}
|
|
7320
7677
|
try {
|
|
7321
7678
|
await this.postBatch(batch, `event_batch:${batch.length}`);
|
|
7322
|
-
} catch {
|
|
7323
|
-
|
|
7679
|
+
} catch (err) {
|
|
7680
|
+
console.error("[Paywallo:NORMAL] batch post failed \u2014 relying on OfflineQueue", { batchSize: batch.length, error: err instanceof Error ? err.message : String(err) });
|
|
7324
7681
|
}
|
|
7325
7682
|
}
|
|
7326
7683
|
async postBatch(events, label, priority = "normal") {
|
|
@@ -7335,6 +7692,7 @@ var init_EventBatcher = __esm({
|
|
|
7335
7692
|
const parsed = v2EnvelopeSchema.safeParse(envelope);
|
|
7336
7693
|
if (!parsed.success) {
|
|
7337
7694
|
if (this.debug) console.log("[Paywallo EVENTS] V2 envelope schema validation failed:", parsed.error.issues);
|
|
7695
|
+
console.error("[Paywallo:CRITICAL] V2 envelope schema validation failed", { issues: parsed.error.issues, eventCount: events.length, firstEventName: events[0]?.eventName, context: providerContext });
|
|
7338
7696
|
throw parsed.error;
|
|
7339
7697
|
}
|
|
7340
7698
|
await this.post(V2_BATCH_ENDPOINT, parsed.data, label, priority);
|
|
@@ -7572,11 +7930,11 @@ var init_http = __esm({
|
|
|
7572
7930
|
});
|
|
7573
7931
|
|
|
7574
7932
|
// src/core/ApiClient.ts
|
|
7575
|
-
var
|
|
7933
|
+
var import_react_native25, ApiClient;
|
|
7576
7934
|
var init_ApiClient = __esm({
|
|
7577
7935
|
"src/core/ApiClient.ts"() {
|
|
7578
7936
|
"use strict";
|
|
7579
|
-
|
|
7937
|
+
import_react_native25 = require("react-native");
|
|
7580
7938
|
init_apiPurchaseMethods();
|
|
7581
7939
|
init_ApiCache();
|
|
7582
7940
|
init_ApiClientFlags();
|
|
@@ -7678,7 +8036,7 @@ var init_ApiClient = __esm({
|
|
|
7678
8036
|
buildSdkHeaders() {
|
|
7679
8037
|
return {
|
|
7680
8038
|
"x-sdk-version": SDK_VERSION,
|
|
7681
|
-
"x-sdk-platform":
|
|
8039
|
+
"x-sdk-platform": import_react_native25.Platform.OS,
|
|
7682
8040
|
"x-sdk-environment": this.environment
|
|
7683
8041
|
};
|
|
7684
8042
|
}
|
|
@@ -7708,7 +8066,7 @@ var init_ApiClient = __esm({
|
|
|
7708
8066
|
message,
|
|
7709
8067
|
context,
|
|
7710
8068
|
sdkVersion: SDK_VERSION,
|
|
7711
|
-
platform:
|
|
8069
|
+
platform: import_react_native25.Platform.OS
|
|
7712
8070
|
}, true);
|
|
7713
8071
|
} catch (err) {
|
|
7714
8072
|
if (this.debug) console.log("[Paywallo:ApiClient] reportError failed", err);
|
|
@@ -7726,7 +8084,7 @@ var init_ApiClient = __esm({
|
|
|
7726
8084
|
async identify(distinctId, properties, email, deviceId, pii) {
|
|
7727
8085
|
const rawTraits = {
|
|
7728
8086
|
email: email || void 0,
|
|
7729
|
-
platform:
|
|
8087
|
+
platform: import_react_native25.Platform.OS,
|
|
7730
8088
|
name: properties?.name,
|
|
7731
8089
|
country: properties?.country,
|
|
7732
8090
|
locale: properties?.locale,
|
|
@@ -7917,7 +8275,8 @@ function setupNotifications(apiClient, config, environment, eventPipeline) {
|
|
|
7917
8275
|
httpClient: apiClient.getHttpClient(),
|
|
7918
8276
|
secureStorage: new SecureStorage(config.debug),
|
|
7919
8277
|
getDeviceId: () => identityManager.getDeviceId(),
|
|
7920
|
-
getDistinctId: () => identityManager.getDistinctId()
|
|
8278
|
+
getDistinctId: () => identityManager.getDistinctId(),
|
|
8279
|
+
environment: environment === "Sandbox" ? "sandbox" : "production"
|
|
7921
8280
|
});
|
|
7922
8281
|
notificationsManager.setupHandlers({ eventBatcher: eventPipeline });
|
|
7923
8282
|
notificationsManager.initialize({
|
|
@@ -8001,6 +8360,36 @@ var init_PaywalloState = __esm({
|
|
|
8001
8360
|
}
|
|
8002
8361
|
});
|
|
8003
8362
|
|
|
8363
|
+
// src/utils/detectEnvironment.ts
|
|
8364
|
+
async function detectEnvironment() {
|
|
8365
|
+
if (cached !== null) return cached;
|
|
8366
|
+
if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
|
|
8367
|
+
cached = "sandbox";
|
|
8368
|
+
return cached;
|
|
8369
|
+
}
|
|
8370
|
+
if (!nativeModule) {
|
|
8371
|
+
cached = "production";
|
|
8372
|
+
return cached;
|
|
8373
|
+
}
|
|
8374
|
+
try {
|
|
8375
|
+
const result = await nativeModule.detect();
|
|
8376
|
+
cached = result === "sandbox" ? "sandbox" : "production";
|
|
8377
|
+
return cached;
|
|
8378
|
+
} catch {
|
|
8379
|
+
cached = "production";
|
|
8380
|
+
return cached;
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
var import_react_native26, nativeModule, cached;
|
|
8384
|
+
var init_detectEnvironment = __esm({
|
|
8385
|
+
"src/utils/detectEnvironment.ts"() {
|
|
8386
|
+
"use strict";
|
|
8387
|
+
import_react_native26 = require("react-native");
|
|
8388
|
+
nativeModule = import_react_native26.NativeModules.PaywalloEnv ?? null;
|
|
8389
|
+
cached = null;
|
|
8390
|
+
}
|
|
8391
|
+
});
|
|
8392
|
+
|
|
8004
8393
|
// src/core/PaywalloInitializer.ts
|
|
8005
8394
|
async function initWithRetry(state, config) {
|
|
8006
8395
|
while (state.initAttempts <= MAX_INIT_RETRIES) {
|
|
@@ -8080,7 +8469,13 @@ async function resolveSessionFlags(state, keys, apiClient, distinctId) {
|
|
|
8080
8469
|
}
|
|
8081
8470
|
}
|
|
8082
8471
|
async function doInit(state, config) {
|
|
8083
|
-
|
|
8472
|
+
let environment;
|
|
8473
|
+
if (config.environment) {
|
|
8474
|
+
environment = config.environment;
|
|
8475
|
+
} else {
|
|
8476
|
+
const detected = await detectEnvironment();
|
|
8477
|
+
environment = detected === "sandbox" ? "Sandbox" : "Production";
|
|
8478
|
+
}
|
|
8084
8479
|
const offlineQueueEnabled = config.offlineQueueEnabled !== false;
|
|
8085
8480
|
await Promise.all([
|
|
8086
8481
|
networkMonitor.initialize({ debug: config.debug }),
|
|
@@ -8168,15 +8563,31 @@ async function doInit(state, config) {
|
|
|
8168
8563
|
timezone = opts.timeZone || void 0;
|
|
8169
8564
|
} catch {
|
|
8170
8565
|
}
|
|
8566
|
+
let screenWidth;
|
|
8567
|
+
let screenHeight;
|
|
8568
|
+
let screenDensity;
|
|
8569
|
+
try {
|
|
8570
|
+
const screen = import_react_native27.Dimensions.get("screen");
|
|
8571
|
+
screenWidth = Math.round(screen.width) || void 0;
|
|
8572
|
+
screenHeight = Math.round(screen.height) || void 0;
|
|
8573
|
+
screenDensity = import_react_native27.PixelRatio.get() || void 0;
|
|
8574
|
+
} catch {
|
|
8575
|
+
}
|
|
8171
8576
|
return {
|
|
8172
8577
|
distinct_id: identityManager.getDistinctId() || void 0,
|
|
8173
8578
|
device_id: identityManager.getDeviceId() ?? void 0,
|
|
8174
8579
|
session_id: sessionManager.getSessionId() ?? void 0,
|
|
8175
8580
|
app_version: device?.appVersion && device.appVersion !== "0.0.0" ? device.appVersion : void 0,
|
|
8581
|
+
app_build: device?.buildNumber && device.buildNumber !== "0" ? device.buildNumber : void 0,
|
|
8582
|
+
bundle_id: device?.bundleId || void 0,
|
|
8176
8583
|
os_version: device?.systemVersion && device.systemVersion !== "0.0.0" ? device.systemVersion : void 0,
|
|
8177
8584
|
device_model: device?.modelId || device?.model || void 0,
|
|
8178
8585
|
timezone,
|
|
8179
8586
|
locale,
|
|
8587
|
+
carrier: device?.carrier || void 0,
|
|
8588
|
+
screen_width: screenWidth,
|
|
8589
|
+
screen_height: screenHeight,
|
|
8590
|
+
screen_density: screenDensity,
|
|
8180
8591
|
...attribution && Object.keys(attribution).length > 0 && { attribution },
|
|
8181
8592
|
...ids && Object.keys(ids).length > 0 && { ids }
|
|
8182
8593
|
};
|
|
@@ -8226,9 +8637,11 @@ async function doInit(state, config) {
|
|
|
8226
8637
|
setupAutoPreload(state, apiClient, config, distinctId);
|
|
8227
8638
|
startBatchPreload(apiClient, config.debug);
|
|
8228
8639
|
}
|
|
8640
|
+
var import_react_native27;
|
|
8229
8641
|
var init_PaywalloInitializer = __esm({
|
|
8230
8642
|
"src/core/PaywalloInitializer.ts"() {
|
|
8231
8643
|
"use strict";
|
|
8644
|
+
import_react_native27 = require("react-native");
|
|
8232
8645
|
init_identity();
|
|
8233
8646
|
init_AdvertisingIdManager();
|
|
8234
8647
|
init_DeepLinkAttributionCapture();
|
|
@@ -8248,6 +8661,7 @@ var init_PaywalloInitializer = __esm({
|
|
|
8248
8661
|
init_PaywalloState();
|
|
8249
8662
|
init_queue();
|
|
8250
8663
|
init_NativeStorage();
|
|
8664
|
+
init_detectEnvironment();
|
|
8251
8665
|
}
|
|
8252
8666
|
});
|
|
8253
8667
|
|
|
@@ -8270,6 +8684,7 @@ async function doFullReset(state) {
|
|
|
8270
8684
|
offlineQueue.dispose();
|
|
8271
8685
|
networkMonitor.dispose();
|
|
8272
8686
|
campaignGateService.clearPreloaded();
|
|
8687
|
+
paywallPreloadService.clear();
|
|
8273
8688
|
await notificationsManager.invalidateLocalToken().catch(() => void 0);
|
|
8274
8689
|
notificationsManager.destroy();
|
|
8275
8690
|
deepLinkAttributionCapture.stop();
|
|
@@ -8304,6 +8719,7 @@ var init_PaywalloLifecycle = __esm({
|
|
|
8304
8719
|
init_identity();
|
|
8305
8720
|
init_DeepLinkAttributionCapture();
|
|
8306
8721
|
init_notifications();
|
|
8722
|
+
init_paywall();
|
|
8307
8723
|
init_session();
|
|
8308
8724
|
init_SubscriptionCache();
|
|
8309
8725
|
init_network();
|
|
@@ -8607,6 +9023,15 @@ var init_PaywalloClient = __esm({
|
|
|
8607
9023
|
isPreloaded(placement) {
|
|
8608
9024
|
return campaignGateService.getPreloadedCampaign(placement) !== null;
|
|
8609
9025
|
}
|
|
9026
|
+
async preloadPaywall(placement) {
|
|
9027
|
+
return paywallPreloadService.preload(this.getApiClientOrThrow(), placement);
|
|
9028
|
+
}
|
|
9029
|
+
async preloadPaywalls(placements) {
|
|
9030
|
+
return paywallPreloadService.preloadMany(this.getApiClientOrThrow(), placements);
|
|
9031
|
+
}
|
|
9032
|
+
isPaywallPreloaded(placement) {
|
|
9033
|
+
return paywallPreloadService.isPreloaded(placement);
|
|
9034
|
+
}
|
|
8610
9035
|
getAutoPreloadedPlacement() {
|
|
8611
9036
|
return this.state.autoPreloadedPlacement;
|
|
8612
9037
|
}
|
|
@@ -8652,7 +9077,7 @@ __export(OfferingService_exports, {
|
|
|
8652
9077
|
offeringService: () => offeringService
|
|
8653
9078
|
});
|
|
8654
9079
|
function resolveProductId(raw) {
|
|
8655
|
-
const isIos =
|
|
9080
|
+
const isIos = import_react_native28.Platform.OS === "ios";
|
|
8656
9081
|
const productId = isIos ? raw.apple_product_id : raw.google_product_id;
|
|
8657
9082
|
return productId ?? "";
|
|
8658
9083
|
}
|
|
@@ -8671,7 +9096,7 @@ function mapProduct2(raw) {
|
|
|
8671
9096
|
};
|
|
8672
9097
|
}
|
|
8673
9098
|
function pickPlatformProduct(products) {
|
|
8674
|
-
const isIos =
|
|
9099
|
+
const isIos = import_react_native28.Platform.OS === "ios";
|
|
8675
9100
|
const match = products.find((p) => isIos ? p.apple_product_id : p.google_product_id);
|
|
8676
9101
|
return match ?? products[0] ?? null;
|
|
8677
9102
|
}
|
|
@@ -8687,11 +9112,11 @@ function mapOffering(raw) {
|
|
|
8687
9112
|
product: mapProduct2(rawProduct)
|
|
8688
9113
|
};
|
|
8689
9114
|
}
|
|
8690
|
-
var
|
|
9115
|
+
var import_react_native28, OFFERINGS_CACHE_KEY, DEFAULT_TTL3, OfferingService, offeringService;
|
|
8691
9116
|
var init_OfferingService = __esm({
|
|
8692
9117
|
"src/domains/offering/OfferingService.ts"() {
|
|
8693
9118
|
"use strict";
|
|
8694
|
-
|
|
9119
|
+
import_react_native28 = require("react-native");
|
|
8695
9120
|
init_SecureStorage();
|
|
8696
9121
|
OFFERINGS_CACHE_KEY = "@paywallo:offerings_cache";
|
|
8697
9122
|
DEFAULT_TTL3 = 5 * 60 * 1e3;
|
|
@@ -8705,8 +9130,8 @@ var init_OfferingService = __esm({
|
|
|
8705
9130
|
this.config = config;
|
|
8706
9131
|
}
|
|
8707
9132
|
async getOfferings(ids) {
|
|
8708
|
-
const
|
|
8709
|
-
if (
|
|
9133
|
+
const cached2 = this.getMemCache();
|
|
9134
|
+
if (cached2 && !cached2.isStale) return this.filterByIds(cached2.data, ids);
|
|
8710
9135
|
if (!this.cache) {
|
|
8711
9136
|
try {
|
|
8712
9137
|
const stored = await secureStorage.get(OFFERINGS_CACHE_KEY);
|
|
@@ -8852,8 +9277,8 @@ module.exports = __toCommonJS(index_exports);
|
|
|
8852
9277
|
init_PaywalloClient();
|
|
8853
9278
|
|
|
8854
9279
|
// src/context/PaywalloContext.ts
|
|
8855
|
-
var
|
|
8856
|
-
var PaywalloContext = (0,
|
|
9280
|
+
var import_react12 = require("react");
|
|
9281
|
+
var PaywalloContext = (0, import_react12.createContext)(null);
|
|
8857
9282
|
|
|
8858
9283
|
// src/index.ts
|
|
8859
9284
|
init_ApiClient();
|
|
@@ -8898,7 +9323,7 @@ init_session();
|
|
|
8898
9323
|
init_PaywalloError();
|
|
8899
9324
|
|
|
8900
9325
|
// src/hooks/useOfferingPurchase.ts
|
|
8901
|
-
var
|
|
9326
|
+
var import_react13 = require("react");
|
|
8902
9327
|
|
|
8903
9328
|
// src/domains/plan/invalidateCache.ts
|
|
8904
9329
|
async function invalidatePlanCache() {
|
|
@@ -8911,8 +9336,8 @@ async function invalidatePlanCache() {
|
|
|
8911
9336
|
|
|
8912
9337
|
// src/hooks/useOfferingPurchase.ts
|
|
8913
9338
|
function useOfferingPurchase() {
|
|
8914
|
-
const [state, setState] = (0,
|
|
8915
|
-
const purchase = (0,
|
|
9339
|
+
const [state, setState] = (0, import_react13.useState)("idle");
|
|
9340
|
+
const purchase = (0, import_react13.useCallback)(async (productId) => {
|
|
8916
9341
|
setState("purchasing");
|
|
8917
9342
|
try {
|
|
8918
9343
|
const iapService = getIAPService();
|
|
@@ -8936,7 +9361,7 @@ function useOfferingPurchase() {
|
|
|
8936
9361
|
}
|
|
8937
9362
|
|
|
8938
9363
|
// src/hooks/useOfferings.ts
|
|
8939
|
-
var
|
|
9364
|
+
var import_react14 = require("react");
|
|
8940
9365
|
async function getOfferingService() {
|
|
8941
9366
|
try {
|
|
8942
9367
|
const mod = await Promise.resolve().then(() => (init_OfferingService(), OfferingService_exports));
|
|
@@ -8946,10 +9371,10 @@ async function getOfferingService() {
|
|
|
8946
9371
|
}
|
|
8947
9372
|
}
|
|
8948
9373
|
function useOfferings(ids) {
|
|
8949
|
-
const [offerings, setOfferings] = (0,
|
|
8950
|
-
const [isLoading, setIsLoading] = (0,
|
|
9374
|
+
const [offerings, setOfferings] = (0, import_react14.useState)([]);
|
|
9375
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
8951
9376
|
const idsKey = ids?.join(",") ?? "";
|
|
8952
|
-
const fetchOfferings = (0,
|
|
9377
|
+
const fetchOfferings = (0, import_react14.useCallback)(async () => {
|
|
8953
9378
|
setIsLoading(true);
|
|
8954
9379
|
try {
|
|
8955
9380
|
const service = await getOfferingService();
|
|
@@ -8965,25 +9390,25 @@ function useOfferings(ids) {
|
|
|
8965
9390
|
setIsLoading(false);
|
|
8966
9391
|
}
|
|
8967
9392
|
}, [idsKey]);
|
|
8968
|
-
(0,
|
|
9393
|
+
(0, import_react14.useEffect)(() => {
|
|
8969
9394
|
void fetchOfferings();
|
|
8970
9395
|
}, [fetchOfferings]);
|
|
8971
9396
|
return { offerings, isLoading };
|
|
8972
9397
|
}
|
|
8973
9398
|
|
|
8974
9399
|
// src/hooks/useOnboarding.ts
|
|
8975
|
-
var
|
|
9400
|
+
var import_react15 = require("react");
|
|
8976
9401
|
init_onboarding();
|
|
8977
9402
|
function useOnboarding() {
|
|
8978
|
-
const step = (0,
|
|
9403
|
+
const step = (0, import_react15.useCallback)(
|
|
8979
9404
|
(stepName) => onboardingManager.step(stepName),
|
|
8980
9405
|
[]
|
|
8981
9406
|
);
|
|
8982
|
-
const complete = (0,
|
|
9407
|
+
const complete = (0, import_react15.useCallback)(
|
|
8983
9408
|
() => onboardingManager.complete(),
|
|
8984
9409
|
[]
|
|
8985
9410
|
);
|
|
8986
|
-
const drop = (0,
|
|
9411
|
+
const drop = (0, import_react15.useCallback)(
|
|
8987
9412
|
(stepName) => onboardingManager.drop(stepName),
|
|
8988
9413
|
[]
|
|
8989
9414
|
);
|
|
@@ -8991,10 +9416,10 @@ function useOnboarding() {
|
|
|
8991
9416
|
}
|
|
8992
9417
|
|
|
8993
9418
|
// src/hooks/usePaywallo.ts
|
|
8994
|
-
var
|
|
9419
|
+
var import_react16 = require("react");
|
|
8995
9420
|
init_ClientError();
|
|
8996
9421
|
function usePaywallo() {
|
|
8997
|
-
const context = (0,
|
|
9422
|
+
const context = (0, import_react16.useContext)(PaywalloContext);
|
|
8998
9423
|
if (!context) {
|
|
8999
9424
|
throw new ClientError(CLIENT_ERROR_CODES.PROVIDER_MISSING, "usePaywallo must be used within a PaywalloProvider");
|
|
9000
9425
|
}
|
|
@@ -9002,11 +9427,11 @@ function usePaywallo() {
|
|
|
9002
9427
|
}
|
|
9003
9428
|
|
|
9004
9429
|
// src/hooks/usePlanPurchase.ts
|
|
9005
|
-
var
|
|
9430
|
+
var import_react17 = require("react");
|
|
9006
9431
|
function usePlanPurchase() {
|
|
9007
|
-
const [state, setState] = (0,
|
|
9008
|
-
const [error, setError] = (0,
|
|
9009
|
-
const purchase = (0,
|
|
9432
|
+
const [state, setState] = (0, import_react17.useState)("idle");
|
|
9433
|
+
const [error, setError] = (0, import_react17.useState)(null);
|
|
9434
|
+
const purchase = (0, import_react17.useCallback)(async (productId) => {
|
|
9010
9435
|
setState("purchasing");
|
|
9011
9436
|
setError(null);
|
|
9012
9437
|
try {
|
|
@@ -9029,7 +9454,7 @@ function usePlanPurchase() {
|
|
|
9029
9454
|
return { success: false, error: purchaseError };
|
|
9030
9455
|
}
|
|
9031
9456
|
}, []);
|
|
9032
|
-
const restore = (0,
|
|
9457
|
+
const restore = (0, import_react17.useCallback)(async () => {
|
|
9033
9458
|
setState("restoring");
|
|
9034
9459
|
setError(null);
|
|
9035
9460
|
try {
|
|
@@ -9058,7 +9483,7 @@ function usePlanPurchase() {
|
|
|
9058
9483
|
}
|
|
9059
9484
|
|
|
9060
9485
|
// src/hooks/usePlans.ts
|
|
9061
|
-
var
|
|
9486
|
+
var import_react18 = require("react");
|
|
9062
9487
|
async function getPlanService() {
|
|
9063
9488
|
try {
|
|
9064
9489
|
const mod = await Promise.resolve().then(() => (init_PlanService(), PlanService_exports));
|
|
@@ -9068,11 +9493,11 @@ async function getPlanService() {
|
|
|
9068
9493
|
}
|
|
9069
9494
|
}
|
|
9070
9495
|
function usePlans() {
|
|
9071
|
-
const [allPlans, setAllPlans] = (0,
|
|
9072
|
-
const [currentPlan, setCurrentPlan] = (0,
|
|
9073
|
-
const [isLoading, setIsLoading] = (0,
|
|
9074
|
-
const [error, setError] = (0,
|
|
9075
|
-
const fetchPlans = (0,
|
|
9496
|
+
const [allPlans, setAllPlans] = (0, import_react18.useState)([]);
|
|
9497
|
+
const [currentPlan, setCurrentPlan] = (0, import_react18.useState)(null);
|
|
9498
|
+
const [isLoading, setIsLoading] = (0, import_react18.useState)(true);
|
|
9499
|
+
const [error, setError] = (0, import_react18.useState)(null);
|
|
9500
|
+
const fetchPlans = (0, import_react18.useCallback)(async (forceRefresh = false) => {
|
|
9076
9501
|
setIsLoading(true);
|
|
9077
9502
|
setError(null);
|
|
9078
9503
|
try {
|
|
@@ -9093,17 +9518,17 @@ function usePlans() {
|
|
|
9093
9518
|
setIsLoading(false);
|
|
9094
9519
|
}
|
|
9095
9520
|
}, []);
|
|
9096
|
-
const refresh = (0,
|
|
9521
|
+
const refresh = (0, import_react18.useCallback)(() => {
|
|
9097
9522
|
return fetchPlans(true);
|
|
9098
9523
|
}, [fetchPlans]);
|
|
9099
|
-
(0,
|
|
9524
|
+
(0, import_react18.useEffect)(() => {
|
|
9100
9525
|
void fetchPlans(false);
|
|
9101
9526
|
}, [fetchPlans]);
|
|
9102
9527
|
return { currentPlan, allPlans, isLoading, error, refresh };
|
|
9103
9528
|
}
|
|
9104
9529
|
|
|
9105
9530
|
// src/hooks/useProducts.ts
|
|
9106
|
-
var
|
|
9531
|
+
var import_react19 = require("react");
|
|
9107
9532
|
|
|
9108
9533
|
// src/utils/productMappers.ts
|
|
9109
9534
|
function mapToIAPProduct(product) {
|
|
@@ -9142,11 +9567,11 @@ function mapToFormattedProduct(product) {
|
|
|
9142
9567
|
|
|
9143
9568
|
// src/hooks/useProducts.ts
|
|
9144
9569
|
function useProducts(initialProductIds) {
|
|
9145
|
-
const [products, setProducts] = (0,
|
|
9146
|
-
const [formattedProducts, setFormattedProducts] = (0,
|
|
9147
|
-
const [isLoading, setIsLoading] = (0,
|
|
9148
|
-
const [error, setError] = (0,
|
|
9149
|
-
const loadProducts = (0,
|
|
9570
|
+
const [products, setProducts] = (0, import_react19.useState)([]);
|
|
9571
|
+
const [formattedProducts, setFormattedProducts] = (0, import_react19.useState)([]);
|
|
9572
|
+
const [isLoading, setIsLoading] = (0, import_react19.useState)(false);
|
|
9573
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
9574
|
+
const loadProducts = (0, import_react19.useCallback)(async (productIds) => {
|
|
9150
9575
|
setIsLoading(true);
|
|
9151
9576
|
setError(null);
|
|
9152
9577
|
try {
|
|
@@ -9160,24 +9585,24 @@ function useProducts(initialProductIds) {
|
|
|
9160
9585
|
setIsLoading(false);
|
|
9161
9586
|
}
|
|
9162
9587
|
}, []);
|
|
9163
|
-
(0,
|
|
9588
|
+
(0, import_react19.useEffect)(() => {
|
|
9164
9589
|
if (initialProductIds && initialProductIds.length > 0) {
|
|
9165
9590
|
void loadProducts(initialProductIds);
|
|
9166
9591
|
}
|
|
9167
9592
|
}, []);
|
|
9168
|
-
const getProduct = (0,
|
|
9593
|
+
const getProduct = (0, import_react19.useCallback)(
|
|
9169
9594
|
(productId) => {
|
|
9170
9595
|
return products.find((p) => p.productId === productId);
|
|
9171
9596
|
},
|
|
9172
9597
|
[products]
|
|
9173
9598
|
);
|
|
9174
|
-
const getFormattedProduct = (0,
|
|
9599
|
+
const getFormattedProduct = (0, import_react19.useCallback)(
|
|
9175
9600
|
(productId) => {
|
|
9176
9601
|
return formattedProducts.find((p) => p.productId === productId);
|
|
9177
9602
|
},
|
|
9178
9603
|
[formattedProducts]
|
|
9179
9604
|
);
|
|
9180
|
-
const getPriceInfo = (0,
|
|
9605
|
+
const getPriceInfo = (0, import_react19.useCallback)(
|
|
9181
9606
|
(productId) => {
|
|
9182
9607
|
const p = formattedProducts.find((fp) => fp.productId === productId);
|
|
9183
9608
|
if (!p) return void 0;
|
|
@@ -9206,14 +9631,14 @@ function useProducts(initialProductIds) {
|
|
|
9206
9631
|
}
|
|
9207
9632
|
|
|
9208
9633
|
// src/hooks/usePurchase.ts
|
|
9209
|
-
var
|
|
9634
|
+
var import_react20 = require("react");
|
|
9210
9635
|
function toIAPPurchase(p) {
|
|
9211
9636
|
return { productId: p.productId, transactionId: p.transactionId, transactionDate: p.transactionDate, transactionReceipt: p.receipt };
|
|
9212
9637
|
}
|
|
9213
9638
|
function usePurchase() {
|
|
9214
|
-
const [state, setState] = (0,
|
|
9215
|
-
const [error, setError] = (0,
|
|
9216
|
-
const purchase = (0,
|
|
9639
|
+
const [state, setState] = (0, import_react20.useState)("idle");
|
|
9640
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
9641
|
+
const purchase = (0, import_react20.useCallback)(async (productId) => {
|
|
9217
9642
|
setState("purchasing");
|
|
9218
9643
|
setError(null);
|
|
9219
9644
|
try {
|
|
@@ -9241,7 +9666,7 @@ function usePurchase() {
|
|
|
9241
9666
|
return { status: "failed", error: purchaseError };
|
|
9242
9667
|
}
|
|
9243
9668
|
}, []);
|
|
9244
|
-
const restore = (0,
|
|
9669
|
+
const restore = (0, import_react20.useCallback)(async () => {
|
|
9245
9670
|
setState("restoring");
|
|
9246
9671
|
setError(null);
|
|
9247
9672
|
try {
|
|
@@ -9260,14 +9685,14 @@ function usePurchase() {
|
|
|
9260
9685
|
}
|
|
9261
9686
|
|
|
9262
9687
|
// src/hooks/useSubscription.ts
|
|
9263
|
-
var
|
|
9688
|
+
var import_react21 = require("react");
|
|
9264
9689
|
init_SubscriptionManager();
|
|
9265
9690
|
var EMPTY_ENTITLEMENTS = [];
|
|
9266
9691
|
function useSubscription() {
|
|
9267
|
-
const [status, setStatus] = (0,
|
|
9268
|
-
const [isLoading, setIsLoading] = (0,
|
|
9269
|
-
const [error, setError] = (0,
|
|
9270
|
-
const refresh = (0,
|
|
9692
|
+
const [status, setStatus] = (0, import_react21.useState)(null);
|
|
9693
|
+
const [isLoading, setIsLoading] = (0, import_react21.useState)(true);
|
|
9694
|
+
const [error, setError] = (0, import_react21.useState)(null);
|
|
9695
|
+
const refresh = (0, import_react21.useCallback)(async () => {
|
|
9271
9696
|
setIsLoading(true);
|
|
9272
9697
|
setError(null);
|
|
9273
9698
|
try {
|
|
@@ -9280,7 +9705,7 @@ function useSubscription() {
|
|
|
9280
9705
|
setIsLoading(false);
|
|
9281
9706
|
}
|
|
9282
9707
|
}, []);
|
|
9283
|
-
const restore = (0,
|
|
9708
|
+
const restore = (0, import_react21.useCallback)(async () => {
|
|
9284
9709
|
setIsLoading(true);
|
|
9285
9710
|
setError(null);
|
|
9286
9711
|
try {
|
|
@@ -9293,7 +9718,7 @@ function useSubscription() {
|
|
|
9293
9718
|
setIsLoading(false);
|
|
9294
9719
|
}
|
|
9295
9720
|
}, []);
|
|
9296
|
-
(0,
|
|
9721
|
+
(0, import_react21.useEffect)(() => {
|
|
9297
9722
|
void subscriptionManager.getSubscriptionStatus().then((s) => {
|
|
9298
9723
|
setStatus(s);
|
|
9299
9724
|
setIsLoading(false);
|
|
@@ -9321,20 +9746,215 @@ function useSubscription() {
|
|
|
9321
9746
|
}
|
|
9322
9747
|
|
|
9323
9748
|
// src/PaywalloProvider.tsx
|
|
9324
|
-
var
|
|
9325
|
-
var
|
|
9749
|
+
var import_react27 = require("react");
|
|
9750
|
+
var import_react_native29 = require("react-native");
|
|
9326
9751
|
init_PaywalloClient();
|
|
9752
|
+
init_NativeStorage();
|
|
9327
9753
|
init_SecureStorage();
|
|
9328
9754
|
init_campaign();
|
|
9329
9755
|
init_paywall();
|
|
9330
9756
|
init_paywall();
|
|
9331
9757
|
init_paywall();
|
|
9332
9758
|
init_paywall();
|
|
9759
|
+
init_paywall();
|
|
9760
|
+
init_paywall();
|
|
9761
|
+
|
|
9762
|
+
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9763
|
+
init_PaywalloClient();
|
|
9764
|
+
|
|
9765
|
+
// src/core/utils/eventId.ts
|
|
9766
|
+
function hashString(input) {
|
|
9767
|
+
let h1 = 3735928559;
|
|
9768
|
+
let h2 = 1103547991;
|
|
9769
|
+
for (let i = 0; i < input.length; i++) {
|
|
9770
|
+
const ch = input.charCodeAt(i);
|
|
9771
|
+
h1 = Math.imul(h1 ^ ch, 2654435769);
|
|
9772
|
+
h2 = Math.imul(h2 ^ ch, 1598716949);
|
|
9773
|
+
}
|
|
9774
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 73244475);
|
|
9775
|
+
h1 ^= Math.imul(h2 ^ h2 >>> 13, 351452291);
|
|
9776
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 73244475);
|
|
9777
|
+
h2 ^= Math.imul(h1 ^ h1 >>> 13, 351452291);
|
|
9778
|
+
const toHex = (n) => (n >>> 0).toString(16).padStart(8, "0");
|
|
9779
|
+
return toHex(h1) + toHex(h2);
|
|
9780
|
+
}
|
|
9781
|
+
function buildDeterministicEventId(parts) {
|
|
9782
|
+
const raw = hashString(parts.join("|"));
|
|
9783
|
+
const p1 = raw.slice(0, 8);
|
|
9784
|
+
const p2 = raw.slice(8, 12);
|
|
9785
|
+
const p3 = "4" + raw.slice(13, 16);
|
|
9786
|
+
const p4 = (parseInt(raw[16], 16) & 3 | 8).toString(16) + raw.slice(17, 20);
|
|
9787
|
+
const p5 = raw.padEnd(32, "0").slice(20, 32);
|
|
9788
|
+
return `${p1}-${p2}-${p3}-${p4}-${p5}`;
|
|
9789
|
+
}
|
|
9790
|
+
|
|
9791
|
+
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9792
|
+
var bridgeStarted = false;
|
|
9793
|
+
var unsubscribe = null;
|
|
9794
|
+
var debugEnabled = false;
|
|
9795
|
+
function log(msg, data) {
|
|
9796
|
+
if (!debugEnabled) return;
|
|
9797
|
+
if (data !== void 0) {
|
|
9798
|
+
console.log(`[Paywallo:SuperwallBridge] ${msg}`, data);
|
|
9799
|
+
} else {
|
|
9800
|
+
console.log(`[Paywallo:SuperwallBridge] ${msg}`);
|
|
9801
|
+
}
|
|
9802
|
+
}
|
|
9803
|
+
function minuteBucket(ts) {
|
|
9804
|
+
return String(Math.floor(ts / 6e4));
|
|
9805
|
+
}
|
|
9806
|
+
function buildEventId(type, identifier, ts) {
|
|
9807
|
+
return buildDeterministicEventId(["sw", type, identifier, minuteBucket(ts)]);
|
|
9808
|
+
}
|
|
9809
|
+
async function trackPaywallEvent(type, identifier, ts, extra) {
|
|
9810
|
+
const _eventId = buildEventId(type, identifier, ts);
|
|
9811
|
+
try {
|
|
9812
|
+
const cleanExtra = {};
|
|
9813
|
+
if (extra) {
|
|
9814
|
+
for (const [k, v] of Object.entries(extra)) if (v !== void 0) cleanExtra[k] = v;
|
|
9815
|
+
}
|
|
9816
|
+
await PaywalloClient.track("paywall", {
|
|
9817
|
+
priority: "critical",
|
|
9818
|
+
properties: {
|
|
9819
|
+
type,
|
|
9820
|
+
paywall_id: identifier,
|
|
9821
|
+
...cleanExtra
|
|
9822
|
+
}
|
|
9823
|
+
});
|
|
9824
|
+
} catch (err) {
|
|
9825
|
+
log("track error", { type, identifier, eventId: _eventId, err: String(err) });
|
|
9826
|
+
}
|
|
9827
|
+
}
|
|
9828
|
+
function mapDismissToCloseReason(resultType) {
|
|
9829
|
+
switch (resultType) {
|
|
9830
|
+
case "purchased":
|
|
9831
|
+
return "purchased";
|
|
9832
|
+
case "restored":
|
|
9833
|
+
return "purchased";
|
|
9834
|
+
// restore counts as a purchase outcome for funnel
|
|
9835
|
+
case "declined":
|
|
9836
|
+
return "dismissed";
|
|
9837
|
+
default:
|
|
9838
|
+
return void 0;
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
function buildCallbacks() {
|
|
9842
|
+
return {
|
|
9843
|
+
onPaywallPresent: (info) => {
|
|
9844
|
+
const ts = Date.now();
|
|
9845
|
+
log("onPaywallPresent", { identifier: info.identifier });
|
|
9846
|
+
void trackPaywallEvent("viewed", info.identifier, ts, {
|
|
9847
|
+
placement: info.presentedByEventWithName,
|
|
9848
|
+
variant_id: info.experiment?.variant?.id,
|
|
9849
|
+
campaign_id: info.experiment?.id
|
|
9850
|
+
});
|
|
9851
|
+
},
|
|
9852
|
+
onPaywallDismiss: (info, result) => {
|
|
9853
|
+
const ts = Date.now();
|
|
9854
|
+
log("onPaywallDismiss", { identifier: info.identifier, result: result.type });
|
|
9855
|
+
void trackPaywallEvent("closed", info.identifier, ts, {
|
|
9856
|
+
placement: info.presentedByEventWithName,
|
|
9857
|
+
variant_id: info.experiment?.variant?.id,
|
|
9858
|
+
campaign_id: info.experiment?.id,
|
|
9859
|
+
close_reason: mapDismissToCloseReason(result.type),
|
|
9860
|
+
closed_at: new Date(ts).toISOString()
|
|
9861
|
+
});
|
|
9862
|
+
},
|
|
9863
|
+
onPurchase: (params) => {
|
|
9864
|
+
const ts = Date.now();
|
|
9865
|
+
const safe = params !== null && typeof params === "object" ? params : {};
|
|
9866
|
+
const productId = "productId" in safe && typeof safe.productId === "string" ? safe.productId : "unknown";
|
|
9867
|
+
const identifier = "paywallIdentifier" in safe && typeof safe.paywallIdentifier === "string" ? safe.paywallIdentifier : productId;
|
|
9868
|
+
log("onPurchase", { productId, identifier });
|
|
9869
|
+
void trackPaywallEvent("purchased", identifier, ts, { product_id: productId });
|
|
9870
|
+
},
|
|
9871
|
+
// Global Superwall event listener — used specifically for `transactionComplete`
|
|
9872
|
+
// which is the only event that exposes the full product (currency/price) +
|
|
9873
|
+
// transaction (storeTransactionId) shape needed to create a server-side
|
|
9874
|
+
// `transactions` row. Other events are skipped (paywallOpen/Dismiss already
|
|
9875
|
+
// handled above with their typed callbacks).
|
|
9876
|
+
onSuperwallEvent: (info) => {
|
|
9877
|
+
const ev = info?.event;
|
|
9878
|
+
if (!ev || ev.event !== "transactionComplete") return;
|
|
9879
|
+
const ts = Date.now();
|
|
9880
|
+
const product = ev.product;
|
|
9881
|
+
const transaction = ev.transaction;
|
|
9882
|
+
if (!product) {
|
|
9883
|
+
log("transactionComplete missing product \u2014 skipping transaction track");
|
|
9884
|
+
return;
|
|
9885
|
+
}
|
|
9886
|
+
const productId = product.productIdentifier ?? product.id ?? "unknown";
|
|
9887
|
+
const currency = product.currencyCode ?? "USD";
|
|
9888
|
+
const price = product.price ?? 0;
|
|
9889
|
+
const transactionId = transaction?.storeTransactionId ?? transaction?.originalTransactionIdentifier ?? `${productId}_${String(ts)}`;
|
|
9890
|
+
const isTrial = product.hasFreeTrial === true || (product.trialPeriodPrice ?? 0) > 0;
|
|
9891
|
+
const paywallIdentifier = ev.paywallInfo?.identifier;
|
|
9892
|
+
log("onSuperwallEvent: transactionComplete", { productId, currency, price, transactionId, isTrial });
|
|
9893
|
+
void (async () => {
|
|
9894
|
+
try {
|
|
9895
|
+
await PaywalloClient.track("transaction", {
|
|
9896
|
+
priority: "critical",
|
|
9897
|
+
properties: {
|
|
9898
|
+
type: isTrial ? "trial_started" : "completed",
|
|
9899
|
+
// Server's IngestTranslator looks for `transaction_id`/`product_id`
|
|
9900
|
+
// /`amount`/`currency`/`paywall_id` keys (not `tx_id`). PurchaseHandler
|
|
9901
|
+
// then resolves type=trial/new/renewal based on amount being 0 vs >0.
|
|
9902
|
+
transaction_id: transactionId,
|
|
9903
|
+
product_id: productId,
|
|
9904
|
+
amount: price,
|
|
9905
|
+
currency,
|
|
9906
|
+
...paywallIdentifier ? { paywall_id: paywallIdentifier } : {}
|
|
9907
|
+
}
|
|
9908
|
+
});
|
|
9909
|
+
} catch (err) {
|
|
9910
|
+
log("transactionComplete track error", { err: String(err) });
|
|
9911
|
+
}
|
|
9912
|
+
})();
|
|
9913
|
+
}
|
|
9914
|
+
};
|
|
9915
|
+
}
|
|
9916
|
+
function startSuperwallAutoBridge(debug = false) {
|
|
9917
|
+
debugEnabled = debug;
|
|
9918
|
+
if (bridgeStarted) {
|
|
9919
|
+
log("already started, skipping");
|
|
9920
|
+
return;
|
|
9921
|
+
}
|
|
9922
|
+
void detectAndStart();
|
|
9923
|
+
}
|
|
9924
|
+
async function detectAndStart() {
|
|
9925
|
+
let subscribeFn;
|
|
9926
|
+
try {
|
|
9927
|
+
const mod = await import("expo-superwall");
|
|
9928
|
+
if (!mod || typeof mod.subscribeToSuperwallEvents !== "function") {
|
|
9929
|
+
const internal = await import("expo-superwall/build/src/internal/superwallEventBridge");
|
|
9930
|
+
if (typeof internal.subscribeToSuperwallEvents !== "function") {
|
|
9931
|
+
log("expo-superwall subscribeToSuperwallEvents not found \u2014 bridge inactive");
|
|
9932
|
+
return;
|
|
9933
|
+
}
|
|
9934
|
+
subscribeFn = internal.subscribeToSuperwallEvents;
|
|
9935
|
+
} else {
|
|
9936
|
+
subscribeFn = mod.subscribeToSuperwallEvents;
|
|
9937
|
+
}
|
|
9938
|
+
} catch {
|
|
9939
|
+
log("expo-superwall not installed \u2014 bridge inactive");
|
|
9940
|
+
return;
|
|
9941
|
+
}
|
|
9942
|
+
try {
|
|
9943
|
+
const callbacks = buildCallbacks();
|
|
9944
|
+
unsubscribe = subscribeFn(void 0, () => callbacks);
|
|
9945
|
+
bridgeStarted = true;
|
|
9946
|
+
log("bridge started");
|
|
9947
|
+
} catch (err) {
|
|
9948
|
+
log("subscribe failed", { err: String(err) });
|
|
9949
|
+
}
|
|
9950
|
+
}
|
|
9951
|
+
|
|
9952
|
+
// src/PaywalloProvider.tsx
|
|
9333
9953
|
init_session();
|
|
9334
9954
|
init_ClientError();
|
|
9335
9955
|
|
|
9336
9956
|
// src/hooks/useAppAutoEvents.ts
|
|
9337
|
-
var
|
|
9957
|
+
var import_react22 = require("react");
|
|
9338
9958
|
|
|
9339
9959
|
// src/utils/platformDetection.ts
|
|
9340
9960
|
async function detectPlatform3() {
|
|
@@ -9356,12 +9976,13 @@ async function detectOsVersion() {
|
|
|
9356
9976
|
}
|
|
9357
9977
|
|
|
9358
9978
|
// src/hooks/useAppAutoEvents.ts
|
|
9359
|
-
var FIRST_SEEN_KEY = "@paywallo:
|
|
9979
|
+
var FIRST_SEEN_KEY = "@paywallo:firstSeen_v226";
|
|
9360
9980
|
var DEBOUNCE_MS = 1e3;
|
|
9361
9981
|
function useAppAutoEvents(config) {
|
|
9362
9982
|
const { isInitialized, getAppVersion: getAppVersion2, getSessionId, emitLifecycle, storageGet, storageSet, debug } = config;
|
|
9363
|
-
const didRunRef = (0,
|
|
9364
|
-
(0,
|
|
9983
|
+
const didRunRef = (0, import_react22.useRef)(false);
|
|
9984
|
+
(0, import_react22.useEffect)(() => {
|
|
9985
|
+
if (debug) console.log("[Paywallo EVENTS] useEffect fired", { isInitialized, didRunRefCurrent: didRunRef.current });
|
|
9365
9986
|
if (!isInitialized || didRunRef.current) return;
|
|
9366
9987
|
const timer = setTimeout(() => {
|
|
9367
9988
|
if (didRunRef.current) return;
|
|
@@ -9371,17 +9992,23 @@ function useAppAutoEvents(config) {
|
|
|
9371
9992
|
const appVersion = getAppVersion2();
|
|
9372
9993
|
const deviceType = await detectPlatform3();
|
|
9373
9994
|
const osVersion = await detectOsVersion();
|
|
9995
|
+
if (debug) console.log("[Paywallo EVENTS] computed device context", { deviceType, osVersion, appVersion, sessionId, hasSessionId: !!sessionId });
|
|
9374
9996
|
try {
|
|
9997
|
+
if (debug) console.log("[Paywallo EVENTS] checking install \u2014 about to read FIRST_SEEN_KEY");
|
|
9375
9998
|
const firstSeen = await storageGet(FIRST_SEEN_KEY);
|
|
9376
9999
|
if (!firstSeen) {
|
|
9377
10000
|
await emitLifecycle({ type: "install", device_type: deviceType, os_version: osVersion, app_version: appVersion, ...sessionId ? { session_id: sessionId } : {} }, "critical");
|
|
9378
10001
|
await storageSet(FIRST_SEEN_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
10002
|
+
if (debug) console.log("[Paywallo EVENTS] install event emitted (first time)");
|
|
9379
10003
|
if (debug) console.log("[Paywallo EVENTS] lifecycle install emitted");
|
|
10004
|
+
} else {
|
|
10005
|
+
if (debug) console.log("[Paywallo EVENTS] install skipped \u2014 firstSeen already exists", { firstSeen });
|
|
9380
10006
|
}
|
|
9381
10007
|
} catch (err) {
|
|
9382
10008
|
if (debug) console.log("[Paywallo EVENTS] lifecycle install check failed", err);
|
|
9383
10009
|
}
|
|
9384
10010
|
try {
|
|
10011
|
+
if (debug) console.log("[Paywallo EVENTS] emitting cold_start");
|
|
9385
10012
|
await emitLifecycle({ type: "cold_start", app_version: appVersion, device_type: deviceType, os_version: osVersion, ...sessionId ? { session_id: sessionId } : {} }, "normal");
|
|
9386
10013
|
if (debug) console.log("[Paywallo EVENTS] lifecycle cold_start emitted");
|
|
9387
10014
|
} catch (err) {
|
|
@@ -9394,7 +10021,7 @@ function useAppAutoEvents(config) {
|
|
|
9394
10021
|
}
|
|
9395
10022
|
|
|
9396
10023
|
// src/hooks/useCampaignPreload.ts
|
|
9397
|
-
var
|
|
10024
|
+
var import_react23 = require("react");
|
|
9398
10025
|
init_PaywalloClient();
|
|
9399
10026
|
init_CampaignError();
|
|
9400
10027
|
|
|
@@ -9465,17 +10092,17 @@ function getCacheEntry(cache, placement) {
|
|
|
9465
10092
|
|
|
9466
10093
|
// src/hooks/useCampaignPreload.ts
|
|
9467
10094
|
function useCampaignPreload() {
|
|
9468
|
-
const [preloadedWebView, setPreloadedWebView] = (0,
|
|
9469
|
-
const preloadedCampaignsRef = (0,
|
|
9470
|
-
const isPreloadValid = (0,
|
|
10095
|
+
const [preloadedWebView, setPreloadedWebView] = (0, import_react23.useState)(null);
|
|
10096
|
+
const preloadedCampaignsRef = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
|
|
10097
|
+
const isPreloadValid = (0, import_react23.useCallback)(
|
|
9471
10098
|
(placement) => isCacheEntryValid(preloadedCampaignsRef.current.get(placement)),
|
|
9472
10099
|
[]
|
|
9473
10100
|
);
|
|
9474
|
-
const consumePreloadedCampaign = (0,
|
|
10101
|
+
const consumePreloadedCampaign = (0, import_react23.useCallback)(
|
|
9475
10102
|
(placement) => getCacheEntry(preloadedCampaignsRef.current, placement),
|
|
9476
10103
|
[]
|
|
9477
10104
|
);
|
|
9478
|
-
const preloadCampaign = (0,
|
|
10105
|
+
const preloadCampaign = (0, import_react23.useCallback)(
|
|
9479
10106
|
async (placement, context) => {
|
|
9480
10107
|
try {
|
|
9481
10108
|
const campaign = await PaywalloClient.getCampaign(placement, context);
|
|
@@ -9544,11 +10171,11 @@ function useCampaignPreload() {
|
|
|
9544
10171
|
}
|
|
9545
10172
|
|
|
9546
10173
|
// src/hooks/useProductLoader.ts
|
|
9547
|
-
var
|
|
10174
|
+
var import_react24 = require("react");
|
|
9548
10175
|
function useProductLoader() {
|
|
9549
|
-
const [products, setProducts] = (0,
|
|
9550
|
-
const [isLoadingProducts, setIsLoadingProducts] = (0,
|
|
9551
|
-
const refreshProducts = (0,
|
|
10176
|
+
const [products, setProducts] = (0, import_react24.useState)(/* @__PURE__ */ new Map());
|
|
10177
|
+
const [isLoadingProducts, setIsLoadingProducts] = (0, import_react24.useState)(false);
|
|
10178
|
+
const refreshProducts = (0, import_react24.useCallback)(async (productIds) => {
|
|
9552
10179
|
setIsLoadingProducts(true);
|
|
9553
10180
|
try {
|
|
9554
10181
|
const iapService = getIAPService();
|
|
@@ -9566,11 +10193,11 @@ function useProductLoader() {
|
|
|
9566
10193
|
}
|
|
9567
10194
|
|
|
9568
10195
|
// src/hooks/usePurchaseOrchestrator.ts
|
|
9569
|
-
var
|
|
10196
|
+
var import_react25 = require("react");
|
|
9570
10197
|
init_paywall();
|
|
9571
10198
|
function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, invalidateSubscriptionCache) {
|
|
9572
10199
|
const { trackDismissed, trackProductSelected, trackPurchased } = usePaywallTracking();
|
|
9573
|
-
const handlePreloadedPurchase = (0,
|
|
10200
|
+
const handlePreloadedPurchase = (0, import_react25.useCallback)(
|
|
9574
10201
|
async (productId) => {
|
|
9575
10202
|
try {
|
|
9576
10203
|
if (preloadedWebView) {
|
|
@@ -9608,7 +10235,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
9608
10235
|
},
|
|
9609
10236
|
[preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, trackDismissed, trackProductSelected, trackPurchased, invalidateSubscriptionCache]
|
|
9610
10237
|
);
|
|
9611
|
-
const handlePreloadedRestore = (0,
|
|
10238
|
+
const handlePreloadedRestore = (0, import_react25.useCallback)(async () => {
|
|
9612
10239
|
try {
|
|
9613
10240
|
const transactions = await getIAPService().restore();
|
|
9614
10241
|
if (transactions.length === 0) return;
|
|
@@ -9631,7 +10258,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
9631
10258
|
}
|
|
9632
10259
|
|
|
9633
10260
|
// src/hooks/useSubscriptionSync.ts
|
|
9634
|
-
var
|
|
10261
|
+
var import_react26 = require("react");
|
|
9635
10262
|
init_PaywalloClient();
|
|
9636
10263
|
init_SubscriptionCache();
|
|
9637
10264
|
|
|
@@ -9696,9 +10323,9 @@ function subscriptionInfoToSub(s) {
|
|
|
9696
10323
|
}
|
|
9697
10324
|
async function resolveOfflineFromCache(distinctId) {
|
|
9698
10325
|
try {
|
|
9699
|
-
const
|
|
9700
|
-
if (!
|
|
9701
|
-
const sub =
|
|
10326
|
+
const cached2 = await subscriptionCache.get(distinctId);
|
|
10327
|
+
if (!cached2) return false;
|
|
10328
|
+
const sub = cached2.data.subscription;
|
|
9702
10329
|
return isSubscriptionStillActive(
|
|
9703
10330
|
sub ? { status: sub.status, expiresAt: sub.expiresAt ?? null } : null
|
|
9704
10331
|
);
|
|
@@ -9741,18 +10368,18 @@ async function checkPersistedCache(distinctId, onHit) {
|
|
|
9741
10368
|
|
|
9742
10369
|
// src/hooks/useSubscriptionSync.ts
|
|
9743
10370
|
function useSubscriptionSync() {
|
|
9744
|
-
const [subscription, setSubscription] = (0,
|
|
9745
|
-
const cacheRef = (0,
|
|
9746
|
-
const setCacheAndState = (0,
|
|
10371
|
+
const [subscription, setSubscription] = (0, import_react26.useState)(null);
|
|
10372
|
+
const cacheRef = (0, import_react26.useRef)(null);
|
|
10373
|
+
const setCacheAndState = (0, import_react26.useCallback)((sub) => {
|
|
9747
10374
|
cacheRef.current = { data: sub, expiresAt: Date.now() + CACHE_TTL_MS2 };
|
|
9748
10375
|
setSubscription(sub);
|
|
9749
10376
|
}, []);
|
|
9750
|
-
const invalidateCache = (0,
|
|
10377
|
+
const invalidateCache = (0, import_react26.useCallback)(() => {
|
|
9751
10378
|
cacheRef.current = null;
|
|
9752
10379
|
const distinctId = PaywalloClient.getDistinctId();
|
|
9753
10380
|
if (distinctId) void subscriptionCache.invalidate(distinctId);
|
|
9754
10381
|
}, []);
|
|
9755
|
-
const fetchAndCache = (0,
|
|
10382
|
+
const fetchAndCache = (0, import_react26.useCallback)(async () => {
|
|
9756
10383
|
const apiClient = PaywalloClient.getApiClient();
|
|
9757
10384
|
const distinctId = PaywalloClient.getDistinctId();
|
|
9758
10385
|
if (!apiClient || !distinctId) return null;
|
|
@@ -9762,14 +10389,14 @@ function useSubscriptionSync() {
|
|
|
9762
10389
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
9763
10390
|
return sub;
|
|
9764
10391
|
}, [setCacheAndState]);
|
|
9765
|
-
const hasActiveSubscription = (0,
|
|
10392
|
+
const hasActiveSubscription = (0, import_react26.useCallback)(async () => {
|
|
9766
10393
|
const apiClient = PaywalloClient.getApiClient();
|
|
9767
10394
|
const distinctId = PaywalloClient.getDistinctId();
|
|
9768
10395
|
if (!apiClient || !distinctId) return false;
|
|
9769
10396
|
const storeKitResult = await checkStoreKitActive(PaywalloClient.getConfig()?.debug);
|
|
9770
10397
|
if (storeKitResult !== null) return storeKitResult;
|
|
9771
|
-
const
|
|
9772
|
-
if (
|
|
10398
|
+
const cached2 = cacheRef.current;
|
|
10399
|
+
if (cached2 && cached2.expiresAt > Date.now()) return isActiveCacheEntry(cached2);
|
|
9773
10400
|
const persistedResult = await checkPersistedCache(distinctId, (sub) => setCacheAndState(sub));
|
|
9774
10401
|
if (persistedResult !== null) return persistedResult;
|
|
9775
10402
|
try {
|
|
@@ -9782,12 +10409,12 @@ function useSubscriptionSync() {
|
|
|
9782
10409
|
return resolveOfflineFromCache(distinctId);
|
|
9783
10410
|
}
|
|
9784
10411
|
}, [setCacheAndState]);
|
|
9785
|
-
const getSubscription = (0,
|
|
10412
|
+
const getSubscription = (0, import_react26.useCallback)(async () => {
|
|
9786
10413
|
const apiClient = PaywalloClient.getApiClient();
|
|
9787
10414
|
const distinctId = PaywalloClient.getDistinctId();
|
|
9788
10415
|
if (!apiClient || !distinctId) return null;
|
|
9789
|
-
const
|
|
9790
|
-
if (
|
|
10416
|
+
const cached2 = cacheRef.current;
|
|
10417
|
+
if (cached2 && cached2.expiresAt > Date.now()) return cached2.data;
|
|
9791
10418
|
try {
|
|
9792
10419
|
return await fetchAndCache();
|
|
9793
10420
|
} catch {
|
|
@@ -9805,22 +10432,22 @@ function useSubscriptionSync() {
|
|
|
9805
10432
|
|
|
9806
10433
|
// src/PaywalloProvider.tsx
|
|
9807
10434
|
init_localization();
|
|
9808
|
-
var
|
|
10435
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
9809
10436
|
function PaywalloProvider({ children, config }) {
|
|
9810
|
-
const [isInitialized, setIsInitialized] = (0,
|
|
9811
|
-
const [initError, setInitError] = (0,
|
|
9812
|
-
const [distinctId, setDistinctId] = (0,
|
|
9813
|
-
const [activePaywall, setActivePaywall] = (0,
|
|
10437
|
+
const [isInitialized, setIsInitialized] = (0, import_react27.useState)(false);
|
|
10438
|
+
const [initError, setInitError] = (0, import_react27.useState)(null);
|
|
10439
|
+
const [distinctId, setDistinctId] = (0, import_react27.useState)(null);
|
|
10440
|
+
const [activePaywall, setActivePaywall] = (0, import_react27.useState)(null);
|
|
9814
10441
|
const { products, isLoadingProducts, refreshProducts } = useProductLoader();
|
|
9815
10442
|
const { subscription, hasActiveSubscription, getSubscription, invalidateCache } = useSubscriptionSync();
|
|
9816
10443
|
const { preloadedWebView, setPreloadedWebView, preloadCampaign, consumePreloadedCampaign, isPreloadValid } = useCampaignPreload();
|
|
9817
|
-
const clearPreloadedWebView = (0,
|
|
9818
|
-
const autoPreloadTriggeredRef = (0,
|
|
9819
|
-
const preloadedWebViewRef = (0,
|
|
9820
|
-
const pollTimerRef = (0,
|
|
9821
|
-
const pollCancelledRef = (0,
|
|
9822
|
-
const secureStorageRef = (0,
|
|
9823
|
-
(0,
|
|
10444
|
+
const clearPreloadedWebView = (0, import_react27.useCallback)(() => setPreloadedWebView(null), [setPreloadedWebView]);
|
|
10445
|
+
const autoPreloadTriggeredRef = (0, import_react27.useRef)(false);
|
|
10446
|
+
const preloadedWebViewRef = (0, import_react27.useRef)(preloadedWebView);
|
|
10447
|
+
const pollTimerRef = (0, import_react27.useRef)(null);
|
|
10448
|
+
const pollCancelledRef = (0, import_react27.useRef)(false);
|
|
10449
|
+
const secureStorageRef = (0, import_react27.useRef)(new SecureStorage(config.debug));
|
|
10450
|
+
(0, import_react27.useEffect)(() => {
|
|
9824
10451
|
preloadedWebViewRef.current = preloadedWebView;
|
|
9825
10452
|
}, [preloadedWebView]);
|
|
9826
10453
|
useAppAutoEvents({
|
|
@@ -9832,26 +10459,36 @@ function PaywalloProvider({ children, config }) {
|
|
|
9832
10459
|
for (const [k, v] of Object.entries(props)) if (v !== void 0) flat[k] = v;
|
|
9833
10460
|
return PaywalloClient.track("lifecycle", { properties: flat, priority });
|
|
9834
10461
|
},
|
|
9835
|
-
storageGet: (key) =>
|
|
9836
|
-
|
|
10462
|
+
storageGet: async (key) => {
|
|
10463
|
+
if (key === "@paywallo:firstSeen_v226") {
|
|
10464
|
+
return nativeStorage.get(key);
|
|
10465
|
+
}
|
|
10466
|
+
return secureStorageRef.current.get(key);
|
|
10467
|
+
},
|
|
10468
|
+
storageSet: async (key, value) => {
|
|
10469
|
+
if (key === "@paywallo:firstSeen_v226") {
|
|
10470
|
+
return nativeStorage.set(key, value);
|
|
10471
|
+
}
|
|
10472
|
+
return secureStorageRef.current.set(key, value);
|
|
10473
|
+
},
|
|
9837
10474
|
debug: config.debug
|
|
9838
10475
|
});
|
|
9839
|
-
const triggerRepreload = (0,
|
|
10476
|
+
const triggerRepreload = (0, import_react27.useCallback)((placement) => {
|
|
9840
10477
|
void PaywalloClient.preloadCampaign(placement).catch(() => {
|
|
9841
10478
|
});
|
|
9842
10479
|
}, []);
|
|
9843
10480
|
const { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady: baseHandlePreloadedWebViewReady, handlePreloadedClose: baseHandlePreloadedClose, setShowingPreloadedWebView, presentedAtRef } = usePaywallPresenter(preloadedWebView, setPreloadedWebView);
|
|
9844
|
-
const SCREEN_HEIGHT = (0,
|
|
9845
|
-
const slideAnim = (0,
|
|
9846
|
-
const handlePreloadedWebViewReady = (0,
|
|
10481
|
+
const SCREEN_HEIGHT = (0, import_react27.useMemo)(() => import_react_native29.Dimensions.get("window").height, []);
|
|
10482
|
+
const slideAnim = (0, import_react27.useRef)(new import_react_native29.Animated.Value(SCREEN_HEIGHT)).current;
|
|
10483
|
+
const handlePreloadedWebViewReady = (0, import_react27.useCallback)(() => {
|
|
9847
10484
|
if (PaywalloClient.getConfig()?.debug) {
|
|
9848
10485
|
console.log(`[Paywallo WEBVIEW] loaded \u2014 placement: ${preloadedWebView?.placement}`);
|
|
9849
10486
|
}
|
|
9850
10487
|
baseHandlePreloadedWebViewReady();
|
|
9851
10488
|
}, [preloadedWebView?.placement, baseHandlePreloadedWebViewReady]);
|
|
9852
|
-
const handlePreloadedClose = (0,
|
|
10489
|
+
const handlePreloadedClose = (0, import_react27.useCallback)(() => {
|
|
9853
10490
|
const placement = preloadedWebView?.placement;
|
|
9854
|
-
|
|
10491
|
+
import_react_native29.Animated.timing(slideAnim, { toValue: SCREEN_HEIGHT, duration: 200, easing: import_react_native29.Easing.in(import_react_native29.Easing.cubic), useNativeDriver: true }).start(() => {
|
|
9855
10492
|
baseHandlePreloadedClose();
|
|
9856
10493
|
if (placement) triggerRepreload(placement);
|
|
9857
10494
|
});
|
|
@@ -9864,8 +10501,8 @@ function PaywalloProvider({ children, config }) {
|
|
|
9864
10501
|
presentedAtRef,
|
|
9865
10502
|
invalidateCache
|
|
9866
10503
|
);
|
|
9867
|
-
const [isPreloadPurchasing, setIsPreloadPurchasing] = (0,
|
|
9868
|
-
const handlePreloadedPurchase = (0,
|
|
10504
|
+
const [isPreloadPurchasing, setIsPreloadPurchasing] = (0, import_react27.useState)(false);
|
|
10505
|
+
const handlePreloadedPurchase = (0, import_react27.useCallback)(async (productId) => {
|
|
9869
10506
|
setIsPreloadPurchasing(true);
|
|
9870
10507
|
try {
|
|
9871
10508
|
await rawPreloadedPurchase(productId);
|
|
@@ -9873,19 +10510,25 @@ function PaywalloProvider({ children, config }) {
|
|
|
9873
10510
|
setIsPreloadPurchasing(false);
|
|
9874
10511
|
}
|
|
9875
10512
|
}, [rawPreloadedPurchase]);
|
|
9876
|
-
const configRef = (0,
|
|
9877
|
-
(0,
|
|
10513
|
+
const configRef = (0, import_react27.useRef)(config);
|
|
10514
|
+
(0, import_react27.useEffect)(() => {
|
|
9878
10515
|
let mounted = true;
|
|
9879
10516
|
initLocalization({ detectDevice: true });
|
|
9880
10517
|
PaywalloClient.init(configRef.current).then(async () => {
|
|
9881
10518
|
if (!mounted) return;
|
|
9882
10519
|
setDistinctId(PaywalloClient.getDistinctId());
|
|
10520
|
+
startSuperwallAutoBridge(configRef.current.debug);
|
|
9883
10521
|
setIsInitialized(true);
|
|
9884
10522
|
if (!autoPreloadTriggeredRef.current) {
|
|
9885
10523
|
autoPreloadTriggeredRef.current = true;
|
|
9886
10524
|
const placement = await PaywalloClient.waitForAutoPreloadedPlacement();
|
|
9887
10525
|
if (mounted && placement) void preloadCampaign(placement).catch(() => {
|
|
9888
10526
|
});
|
|
10527
|
+
const preloadPlacements = configRef.current.preloadPaywalls;
|
|
10528
|
+
if (mounted && preloadPlacements && preloadPlacements.length > 0) {
|
|
10529
|
+
void PaywalloClient.preloadPaywalls(preloadPlacements).catch(() => {
|
|
10530
|
+
});
|
|
10531
|
+
}
|
|
9889
10532
|
}
|
|
9890
10533
|
}).catch((err) => {
|
|
9891
10534
|
if (!mounted) return;
|
|
@@ -9895,14 +10538,28 @@ function PaywalloProvider({ children, config }) {
|
|
|
9895
10538
|
mounted = false;
|
|
9896
10539
|
};
|
|
9897
10540
|
}, [preloadCampaign]);
|
|
9898
|
-
const getPaywallConfig = (0,
|
|
10541
|
+
const getPaywallConfig = (0, import_react27.useCallback)(async (p) => {
|
|
9899
10542
|
const api = PaywalloClient.getApiClient();
|
|
9900
10543
|
return api ? api.getPaywall(p) : null;
|
|
9901
10544
|
}, []);
|
|
9902
|
-
const presentPaywall = (0,
|
|
9903
|
-
|
|
10545
|
+
const presentPaywall = (0, import_react27.useCallback)((placement) => {
|
|
10546
|
+
const preloaded = paywallPreloadService.getPreloaded(placement);
|
|
10547
|
+
return new Promise((resolve) => setActivePaywall({
|
|
10548
|
+
placement,
|
|
10549
|
+
resolver: resolve,
|
|
10550
|
+
...preloaded && {
|
|
10551
|
+
paywallConfig: {
|
|
10552
|
+
id: preloaded.config.id,
|
|
10553
|
+
placement: preloaded.config.placement,
|
|
10554
|
+
config: preloaded.config.config,
|
|
10555
|
+
primaryProductId: preloaded.config.primaryProductId,
|
|
10556
|
+
secondaryProductId: preloaded.config.secondaryProductId
|
|
10557
|
+
},
|
|
10558
|
+
preloadedProducts: preloaded.products
|
|
10559
|
+
}
|
|
10560
|
+
}));
|
|
9904
10561
|
}, []);
|
|
9905
|
-
const trackCampaignImpression = (0,
|
|
10562
|
+
const trackCampaignImpression = (0, import_react27.useCallback)((placement, variantKey, campaignId) => {
|
|
9906
10563
|
const api = PaywalloClient.getApiClient();
|
|
9907
10564
|
if (!api) return;
|
|
9908
10565
|
const sessionId = PaywalloClient.getSessionId();
|
|
@@ -9916,7 +10573,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9916
10573
|
}).catch(() => {
|
|
9917
10574
|
});
|
|
9918
10575
|
}, []);
|
|
9919
|
-
const presentCampaign = (0,
|
|
10576
|
+
const presentCampaign = (0, import_react27.useCallback)(
|
|
9920
10577
|
async (placement, context) => {
|
|
9921
10578
|
try {
|
|
9922
10579
|
if (preloadedWebView?.placement === placement && preloadedWebView.loaded && isPreloadValid(placement)) {
|
|
@@ -9990,7 +10647,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
9990
10647
|
},
|
|
9991
10648
|
[preloadedWebView, isPreloadValid, consumePreloadedCampaign, presentPreloadedWebView, trackCampaignImpression]
|
|
9992
10649
|
);
|
|
9993
|
-
const restorePurchases = (0,
|
|
10650
|
+
const restorePurchases = (0, import_react27.useCallback)(async () => {
|
|
9994
10651
|
invalidateCache();
|
|
9995
10652
|
try {
|
|
9996
10653
|
const txs = await getIAPService().restore();
|
|
@@ -9999,13 +10656,13 @@ function PaywalloProvider({ children, config }) {
|
|
|
9999
10656
|
return { success: false, restoredProducts: [], error: error instanceof Error ? error : new PurchaseError(PURCHASE_ERROR_CODES.RESTORE_FAILED, String(error)) };
|
|
10000
10657
|
}
|
|
10001
10658
|
}, [invalidateCache]);
|
|
10002
|
-
const handlePaywallResult = (0,
|
|
10659
|
+
const handlePaywallResult = (0, import_react27.useCallback)((result) => {
|
|
10003
10660
|
if (activePaywall) {
|
|
10004
10661
|
activePaywall.resolver(result);
|
|
10005
10662
|
setActivePaywall(null);
|
|
10006
10663
|
}
|
|
10007
10664
|
}, [activePaywall]);
|
|
10008
|
-
const bridgePaywallPresenter = (0,
|
|
10665
|
+
const bridgePaywallPresenter = (0, import_react27.useCallback)((placement) => {
|
|
10009
10666
|
if (PaywalloClient.getConfig()?.debug) {
|
|
10010
10667
|
console.log(`[Paywallo PRESENT] called \u2014 preloaded: ${preloadedWebViewRef.current?.loaded === true} placement: ${placement}`);
|
|
10011
10668
|
}
|
|
@@ -10034,7 +10691,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10034
10691
|
}
|
|
10035
10692
|
return presentCampaign(placement);
|
|
10036
10693
|
}, [presentPreloadedWebView, presentCampaign]);
|
|
10037
|
-
(0,
|
|
10694
|
+
(0, import_react27.useEffect)(() => {
|
|
10038
10695
|
if (!isInitialized) return;
|
|
10039
10696
|
const onEmergency = async (id) => {
|
|
10040
10697
|
try {
|
|
@@ -10061,9 +10718,9 @@ function PaywalloProvider({ children, config }) {
|
|
|
10061
10718
|
};
|
|
10062
10719
|
}, [isInitialized, bridgePaywallPresenter, getSubscription, hasActiveSubscription, restorePurchases]);
|
|
10063
10720
|
const isReady = isInitialized && !isLoadingProducts;
|
|
10064
|
-
const noOp = (0,
|
|
10721
|
+
const noOp = (0, import_react27.useCallback)(() => {
|
|
10065
10722
|
}, []);
|
|
10066
|
-
const contextValue = (0,
|
|
10723
|
+
const contextValue = (0, import_react27.useMemo)(() => ({
|
|
10067
10724
|
config: PaywalloClient.getConfig(),
|
|
10068
10725
|
isInitialized,
|
|
10069
10726
|
isReady,
|
|
@@ -10097,20 +10754,20 @@ function PaywalloProvider({ children, config }) {
|
|
|
10097
10754
|
getPaywallConfig,
|
|
10098
10755
|
refreshProducts
|
|
10099
10756
|
]);
|
|
10100
|
-
(0,
|
|
10757
|
+
(0, import_react27.useLayoutEffect)(() => {
|
|
10101
10758
|
if (showingPreloadedWebView) {
|
|
10102
10759
|
slideAnim.setValue(SCREEN_HEIGHT);
|
|
10103
|
-
|
|
10760
|
+
import_react_native29.Animated.timing(slideAnim, { toValue: 0, duration: 200, easing: import_react_native29.Easing.out(import_react_native29.Easing.cubic), useNativeDriver: true }).start();
|
|
10104
10761
|
}
|
|
10105
10762
|
}, [showingPreloadedWebView, slideAnim, SCREEN_HEIGHT]);
|
|
10106
10763
|
const preloadStyle = [
|
|
10107
|
-
|
|
10108
|
-
showingPreloadedWebView ?
|
|
10764
|
+
styles5.preloadOverlay,
|
|
10765
|
+
showingPreloadedWebView ? styles5.visible : styles5.hidden,
|
|
10109
10766
|
showingPreloadedWebView ? { transform: [{ translateY: slideAnim }] } : void 0
|
|
10110
10767
|
];
|
|
10111
|
-
return /* @__PURE__ */ (0,
|
|
10768
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(PaywalloContext.Provider, { value: contextValue, children: [
|
|
10112
10769
|
children,
|
|
10113
|
-
/* @__PURE__ */ (0,
|
|
10770
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PaywallErrorBoundary, { children: !!preloadedWebView?.craftData && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native29.Animated.View, { style: preloadStyle, pointerEvents: showingPreloadedWebView ? "auto" : "none", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
10114
10771
|
PaywallWebView,
|
|
10115
10772
|
{
|
|
10116
10773
|
paywallId: preloadedWebView.paywallId,
|
|
@@ -10126,7 +10783,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10126
10783
|
onRestore: showingPreloadedWebView ? handlePreloadedRestore : noOp
|
|
10127
10784
|
}
|
|
10128
10785
|
) }) }),
|
|
10129
|
-
/* @__PURE__ */ (0,
|
|
10786
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PaywallErrorBoundary, { children: activePaywall && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
10130
10787
|
PaywallModal,
|
|
10131
10788
|
{
|
|
10132
10789
|
placement: activePaywall.placement,
|
|
@@ -10138,10 +10795,11 @@ function PaywalloProvider({ children, config }) {
|
|
|
10138
10795
|
campaignId: activePaywall.campaignId,
|
|
10139
10796
|
variantId: activePaywall.variantId
|
|
10140
10797
|
}
|
|
10141
|
-
) })
|
|
10798
|
+
) }),
|
|
10799
|
+
isInitialized && (config.preloadPaywalls?.length ?? 0) > 0 && PaywalloClient.getWebUrl() !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PaywallWebViewPrewarmer, { webUrl: PaywalloClient.getWebUrl() })
|
|
10142
10800
|
] });
|
|
10143
10801
|
}
|
|
10144
|
-
var
|
|
10802
|
+
var styles5 = import_react_native29.StyleSheet.create({
|
|
10145
10803
|
preloadOverlay: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "#ffffff" },
|
|
10146
10804
|
hidden: { zIndex: -1, opacity: 0, width: 1, height: 1, overflow: "hidden" },
|
|
10147
10805
|
visible: { zIndex: 9999, opacity: 1 }
|