@virex-tech/paywallo-sdk 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PaywalloSdk.podspec +1 -0
- package/README.md +28 -53
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/paywallo/sdk/PaywalloFBBridgeModule.kt +84 -0
- package/android/src/main/java/com/paywallo/sdk/PaywalloSdkPackage.kt +4 -1
- package/dist/index.d.mts +13 -10
- package/dist/index.d.ts +13 -10
- package/dist/index.js +325 -176
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +315 -161
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloFBBridge.m +23 -0
- package/ios/PaywalloFBBridge.swift +77 -0
- package/ios/PaywalloStoreKit.swift +17 -5
- package/ios/RCTBridgeTypes.swift +6 -0
- package/package.json +6 -20
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,25 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/utils/uuid.ts
|
|
34
|
+
var uuid_exports = {};
|
|
35
|
+
__export(uuid_exports, {
|
|
36
|
+
generateUUID: () => generateUUID
|
|
37
|
+
});
|
|
38
|
+
function generateUUID() {
|
|
39
|
+
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
40
|
+
return template.replace(/[xy]/g, (c) => {
|
|
41
|
+
const r = Math.random() * 16 | 0;
|
|
42
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
43
|
+
return v.toString(16);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
var init_uuid = __esm({
|
|
47
|
+
"src/utils/uuid.ts"() {
|
|
48
|
+
"use strict";
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
30
52
|
// src/index.ts
|
|
31
53
|
var index_exports = {};
|
|
32
54
|
__export(index_exports, {
|
|
@@ -44,6 +66,7 @@ __export(index_exports, {
|
|
|
44
66
|
IDENTITY_ERROR_CODES: () => IDENTITY_ERROR_CODES,
|
|
45
67
|
IdentityError: () => IdentityError,
|
|
46
68
|
IdentityManager: () => IdentityManager,
|
|
69
|
+
MetaBridge: () => MetaBridge,
|
|
47
70
|
PAYWALL_ERROR_CODES: () => PAYWALL_ERROR_CODES,
|
|
48
71
|
PURCHASE_ERROR_CODES: () => PURCHASE_ERROR_CODES,
|
|
49
72
|
PaywallContext: () => PaywallContext,
|
|
@@ -71,6 +94,7 @@ __export(index_exports, {
|
|
|
71
94
|
hasVariables: () => hasVariables,
|
|
72
95
|
identityManager: () => identityManager,
|
|
73
96
|
initLocalization: () => initLocalization,
|
|
97
|
+
metaBridge: () => metaBridge,
|
|
74
98
|
nativeStoreKit: () => nativeStoreKit,
|
|
75
99
|
networkMonitor: () => networkMonitor,
|
|
76
100
|
offlineQueue: () => offlineQueue,
|
|
@@ -184,6 +208,9 @@ function createPurchaseError(code, message) {
|
|
|
184
208
|
// src/domains/iap/NativeStoreKit.ts
|
|
185
209
|
var import_react_native = require("react-native");
|
|
186
210
|
|
|
211
|
+
// src/domains/identity/IdentityManager.ts
|
|
212
|
+
var import_react_native_device_info = __toESM(require("react-native-device-info"));
|
|
213
|
+
|
|
187
214
|
// src/domains/identity/IdentityError.ts
|
|
188
215
|
var IdentityError = class extends PaywalloError {
|
|
189
216
|
constructor(code, message) {
|
|
@@ -199,29 +226,12 @@ var IDENTITY_ERROR_CODES = {
|
|
|
199
226
|
IDENTIFY_FAILED: "IDENTITY_IDENTIFY_FAILED"
|
|
200
227
|
};
|
|
201
228
|
|
|
202
|
-
// src/
|
|
203
|
-
|
|
204
|
-
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
205
|
-
return template.replace(/[xy]/g, (c) => {
|
|
206
|
-
const r = Math.random() * 16 | 0;
|
|
207
|
-
const v = c === "x" ? r : r & 3 | 8;
|
|
208
|
-
return v.toString(16);
|
|
209
|
-
});
|
|
210
|
-
}
|
|
229
|
+
// src/domains/identity/IdentityManager.ts
|
|
230
|
+
init_uuid();
|
|
211
231
|
|
|
212
232
|
// src/core/storage/SecureStorage.ts
|
|
213
233
|
var import_async_storage = __toESM(require("@react-native-async-storage/async-storage"));
|
|
214
|
-
var
|
|
215
|
-
async function loadKeychain() {
|
|
216
|
-
if (_keychain !== void 0) return _keychain;
|
|
217
|
-
try {
|
|
218
|
-
const mod = await import("react-native-keychain");
|
|
219
|
-
_keychain = mod.default;
|
|
220
|
-
} catch {
|
|
221
|
-
_keychain = null;
|
|
222
|
-
}
|
|
223
|
-
return _keychain;
|
|
224
|
-
}
|
|
234
|
+
var import_react_native_keychain = __toESM(require("react-native-keychain"));
|
|
225
235
|
var KEYCHAIN_SERVICE_PREFIX = "com.paywallo.sdk.";
|
|
226
236
|
var SecureStorage = class {
|
|
227
237
|
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
|
@@ -265,13 +275,11 @@ var SecureStorage = class {
|
|
|
265
275
|
}
|
|
266
276
|
}
|
|
267
277
|
hasKeychainSupport() {
|
|
268
|
-
return
|
|
278
|
+
return true;
|
|
269
279
|
}
|
|
270
280
|
async getFromKeychain(key) {
|
|
271
|
-
const keychain = await loadKeychain();
|
|
272
|
-
if (!keychain) return null;
|
|
273
281
|
try {
|
|
274
|
-
const result = await
|
|
282
|
+
const result = await import_react_native_keychain.default.getGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
275
283
|
if (result && result.password) {
|
|
276
284
|
return result.password;
|
|
277
285
|
}
|
|
@@ -281,20 +289,16 @@ var SecureStorage = class {
|
|
|
281
289
|
}
|
|
282
290
|
}
|
|
283
291
|
async setToKeychain(key, value) {
|
|
284
|
-
const keychain = await loadKeychain();
|
|
285
|
-
if (!keychain) return false;
|
|
286
292
|
try {
|
|
287
|
-
await
|
|
293
|
+
await import_react_native_keychain.default.setGenericPassword("panel", value, { service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
288
294
|
return true;
|
|
289
295
|
} catch {
|
|
290
296
|
return false;
|
|
291
297
|
}
|
|
292
298
|
}
|
|
293
299
|
async removeFromKeychain(key) {
|
|
294
|
-
const keychain = await loadKeychain();
|
|
295
|
-
if (!keychain) return false;
|
|
296
300
|
try {
|
|
297
|
-
await
|
|
301
|
+
await import_react_native_keychain.default.resetGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
298
302
|
return true;
|
|
299
303
|
} catch {
|
|
300
304
|
return false;
|
|
@@ -328,19 +332,8 @@ var IdentityManager = class {
|
|
|
328
332
|
this.secureStorage = new SecureStorage(debug);
|
|
329
333
|
await this.loadPersistedState();
|
|
330
334
|
if (!this.deviceId) {
|
|
331
|
-
let DeviceInfo = null;
|
|
332
335
|
try {
|
|
333
|
-
|
|
334
|
-
DeviceInfo = mod.default;
|
|
335
|
-
} catch {
|
|
336
|
-
DeviceInfo = null;
|
|
337
|
-
}
|
|
338
|
-
try {
|
|
339
|
-
if (DeviceInfo) {
|
|
340
|
-
this.deviceId = await DeviceInfo.getUniqueId();
|
|
341
|
-
} else {
|
|
342
|
-
this.deviceId = generateUUID();
|
|
343
|
-
}
|
|
336
|
+
this.deviceId = await import_react_native_device_info.default.getUniqueId();
|
|
344
337
|
} catch {
|
|
345
338
|
this.deviceId = generateUUID();
|
|
346
339
|
}
|
|
@@ -569,20 +562,41 @@ var nativeStoreKit = {
|
|
|
569
562
|
);
|
|
570
563
|
}
|
|
571
564
|
const distinctId = identityManager.getDistinctId();
|
|
572
|
-
const
|
|
573
|
-
if (!
|
|
574
|
-
|
|
565
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
566
|
+
if (distinctId && !uuidRegex.test(distinctId) && PaywalloClient.getConfig()?.debug) {
|
|
567
|
+
console.warn("[Paywallo] distinctId is not a valid UUID for appAccountToken:", distinctId);
|
|
568
|
+
}
|
|
569
|
+
try {
|
|
570
|
+
const result = await PaywalloStoreKitNative.purchase(productId, distinctId ?? null);
|
|
571
|
+
if (!result || result.pending) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
return mapNativePurchase(result);
|
|
575
|
+
} catch (err) {
|
|
576
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
577
|
+
if (message.toLowerCase().includes("cancel")) {
|
|
578
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.USER_CANCELLED, message, true);
|
|
579
|
+
}
|
|
580
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, message);
|
|
575
581
|
}
|
|
576
|
-
return mapNativePurchase(result);
|
|
577
582
|
},
|
|
578
583
|
async finishTransaction(transactionId) {
|
|
579
584
|
if (!PaywalloStoreKitNative) return;
|
|
580
|
-
|
|
585
|
+
try {
|
|
586
|
+
await PaywalloStoreKitNative.finishTransaction(transactionId);
|
|
587
|
+
} catch (err) {
|
|
588
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction native error", err);
|
|
589
|
+
}
|
|
581
590
|
},
|
|
582
591
|
async getActiveTransactions() {
|
|
583
592
|
if (!PaywalloStoreKitNative) return [];
|
|
584
|
-
|
|
585
|
-
|
|
593
|
+
try {
|
|
594
|
+
const results = await PaywalloStoreKitNative.getActiveTransactions();
|
|
595
|
+
return results.map(mapNativePurchase);
|
|
596
|
+
} catch (err) {
|
|
597
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] getActiveTransactions failed", err);
|
|
598
|
+
return [];
|
|
599
|
+
}
|
|
586
600
|
}
|
|
587
601
|
};
|
|
588
602
|
|
|
@@ -625,7 +639,8 @@ var IAPService = class {
|
|
|
625
639
|
this.productsCache.set(product.productId, product);
|
|
626
640
|
}
|
|
627
641
|
return products;
|
|
628
|
-
} catch (
|
|
642
|
+
} catch (err) {
|
|
643
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] loadProducts failed", err);
|
|
629
644
|
return [];
|
|
630
645
|
}
|
|
631
646
|
}
|
|
@@ -670,7 +685,8 @@ var IAPService = class {
|
|
|
670
685
|
async finishTransaction(transactionId) {
|
|
671
686
|
try {
|
|
672
687
|
await nativeStoreKit.finishTransaction(transactionId);
|
|
673
|
-
} catch (
|
|
688
|
+
} catch (err) {
|
|
689
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction failed", err);
|
|
674
690
|
}
|
|
675
691
|
}
|
|
676
692
|
async purchase(productId, options) {
|
|
@@ -680,30 +696,25 @@ var IAPService = class {
|
|
|
680
696
|
error: new PurchaseError(PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE, "In-app purchases are not available on this device")
|
|
681
697
|
};
|
|
682
698
|
}
|
|
699
|
+
const debug = PaywalloClient.getConfig()?.debug;
|
|
700
|
+
if (debug) console.info(`[Paywallo PURCHASE] starting ${productId}`);
|
|
683
701
|
try {
|
|
684
702
|
const purchase = await nativeStoreKit.purchase(productId);
|
|
685
703
|
if (!purchase) {
|
|
704
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} cancelled`);
|
|
686
705
|
return { success: false };
|
|
687
706
|
}
|
|
688
|
-
|
|
689
|
-
let validation = null;
|
|
690
|
-
try {
|
|
691
|
-
validation = await this.validateWithServer(purchase, productId, options);
|
|
692
|
-
} catch (validationError) {
|
|
693
|
-
return {
|
|
694
|
-
success: false,
|
|
695
|
-
error: new PurchaseError(PURCHASE_ERROR_CODES.VALIDATION_FAILED, validationError instanceof Error ? validationError.message : "Server validation failed")
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
if (!validation?.success) {
|
|
699
|
-
return {
|
|
700
|
-
success: false,
|
|
701
|
-
error: new PurchaseError(PURCHASE_ERROR_CODES.VALIDATION_FAILED, validation?.error ? `Server validation: ${validation.error}` : "Server validation failed")
|
|
702
|
-
};
|
|
703
|
-
}
|
|
707
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} approved`, { transactionId: purchase.transactionId });
|
|
704
708
|
await this.finishTransaction(purchase.transactionId);
|
|
709
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} finished`);
|
|
710
|
+
this.validateWithServer(purchase, productId, options).then(() => {
|
|
711
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} server validated`);
|
|
712
|
+
}).catch((err) => {
|
|
713
|
+
if (debug) console.warn("[Paywallo PURCHASE] background validation failed", err);
|
|
714
|
+
});
|
|
705
715
|
return { success: true, purchase };
|
|
706
716
|
} catch (error) {
|
|
717
|
+
if (debug) console.warn(`[Paywallo PURCHASE] ${productId} failed`, error);
|
|
707
718
|
const e = error instanceof PurchaseError ? error : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, error instanceof Error ? error.message : String(error));
|
|
708
719
|
return { success: false, error: e };
|
|
709
720
|
}
|
|
@@ -739,13 +750,15 @@ var IAPService = class {
|
|
|
739
750
|
if (r.status === "fulfilled" && r.value.success) {
|
|
740
751
|
try {
|
|
741
752
|
await nativeStoreKit.finishTransaction(tx.transactionId);
|
|
742
|
-
} catch (
|
|
753
|
+
} catch (err) {
|
|
754
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction failed", err);
|
|
743
755
|
}
|
|
744
756
|
validated.push(tx);
|
|
745
757
|
}
|
|
746
758
|
}
|
|
747
759
|
return validated;
|
|
748
|
-
} catch (
|
|
760
|
+
} catch (err) {
|
|
761
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] restore failed", err);
|
|
749
762
|
return [];
|
|
750
763
|
}
|
|
751
764
|
}
|
|
@@ -775,7 +788,8 @@ function usePaywallTracking() {
|
|
|
775
788
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
776
789
|
...sessionId && { sessionId }
|
|
777
790
|
});
|
|
778
|
-
} catch {
|
|
791
|
+
} catch (err) {
|
|
792
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackDismissed failed", err);
|
|
779
793
|
}
|
|
780
794
|
}, []);
|
|
781
795
|
const trackProductSelected = (0, import_react.useCallback)((opts) => {
|
|
@@ -789,7 +803,8 @@ function usePaywallTracking() {
|
|
|
789
803
|
...opts.variantKey && { variantKey: opts.variantKey },
|
|
790
804
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
791
805
|
...sessionId && { sessionId }
|
|
792
|
-
}).catch(() => {
|
|
806
|
+
}).catch((err) => {
|
|
807
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackProductSelected failed", err);
|
|
793
808
|
});
|
|
794
809
|
}, []);
|
|
795
810
|
const trackPurchased = (0, import_react.useCallback)(async (opts) => {
|
|
@@ -805,7 +820,8 @@ function usePaywallTracking() {
|
|
|
805
820
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
806
821
|
...sessionId && { sessionId }
|
|
807
822
|
});
|
|
808
|
-
} catch {
|
|
823
|
+
} catch (err) {
|
|
824
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackPurchased failed", err);
|
|
809
825
|
}
|
|
810
826
|
}, []);
|
|
811
827
|
return { trackDismissed, trackProductSelected, trackPurchased };
|
|
@@ -945,7 +961,8 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
945
961
|
const map = /* @__PURE__ */ new Map();
|
|
946
962
|
for (const p of storeProducts) map.set(p.productId, p);
|
|
947
963
|
setProducts(map);
|
|
948
|
-
} catch {
|
|
964
|
+
} catch (err) {
|
|
965
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] loadProducts in paywall failed", err);
|
|
949
966
|
setProducts(/* @__PURE__ */ new Map());
|
|
950
967
|
}
|
|
951
968
|
} else {
|
|
@@ -1473,7 +1490,12 @@ var PaywallErrorBoundary = class extends import_react6.Component {
|
|
|
1473
1490
|
static getDerivedStateFromError() {
|
|
1474
1491
|
return { hasError: true };
|
|
1475
1492
|
}
|
|
1476
|
-
componentDidCatch(
|
|
1493
|
+
componentDidCatch(error) {
|
|
1494
|
+
if (PaywalloClient.getConfig()?.debug) console.error("[Paywallo] Paywall render error:", error);
|
|
1495
|
+
try {
|
|
1496
|
+
PaywalloClient.getApiClient()?.reportError("PAYWALL_RENDER_ERROR", error.message);
|
|
1497
|
+
} catch {
|
|
1498
|
+
}
|
|
1477
1499
|
}
|
|
1478
1500
|
render() {
|
|
1479
1501
|
return this.state.hasError ? null : this.props.children;
|
|
@@ -1753,7 +1775,8 @@ var AffiliateManager = class {
|
|
|
1753
1775
|
);
|
|
1754
1776
|
}
|
|
1755
1777
|
}
|
|
1756
|
-
log(...
|
|
1778
|
+
log(...args) {
|
|
1779
|
+
if (this.debug) console.log("[Paywallo:Affiliate]", ...args);
|
|
1757
1780
|
}
|
|
1758
1781
|
};
|
|
1759
1782
|
var affiliateManager = new AffiliateManager();
|
|
@@ -2021,7 +2044,8 @@ var SubscriptionManagerClass = class {
|
|
|
2021
2044
|
await this.cache.invalidate(this.cacheKey());
|
|
2022
2045
|
await this.getSubscriptionStatus(true);
|
|
2023
2046
|
}
|
|
2024
|
-
log(...
|
|
2047
|
+
log(...args) {
|
|
2048
|
+
if (this.config?.debug) console.log("[Paywallo:Subscription]", ...args);
|
|
2025
2049
|
}
|
|
2026
2050
|
};
|
|
2027
2051
|
var subscriptionManager = new SubscriptionManagerClass();
|
|
@@ -2074,12 +2098,18 @@ async function validatePurchase(client, appKey, platform, receipt, productId, tr
|
|
|
2074
2098
|
},
|
|
2075
2099
|
false
|
|
2076
2100
|
);
|
|
2101
|
+
if (!response.ok) {
|
|
2102
|
+
throw new Error(`Server validation failed: HTTP ${response.status}`);
|
|
2103
|
+
}
|
|
2077
2104
|
return response.data;
|
|
2078
2105
|
}
|
|
2079
2106
|
async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
|
|
2080
2107
|
const url = new URL(`${baseUrl}/purchases/status/${appKey}`);
|
|
2081
2108
|
url.searchParams.set("distinctId", distinctId);
|
|
2082
2109
|
const response = await client.get(url.toString());
|
|
2110
|
+
if (!response.ok) {
|
|
2111
|
+
throw new Error(`Subscription status check failed: HTTP ${response.status}`);
|
|
2112
|
+
}
|
|
2083
2113
|
return response.data;
|
|
2084
2114
|
}
|
|
2085
2115
|
async function getEmergencyPaywall(client) {
|
|
@@ -2259,7 +2289,8 @@ var HttpClient = class {
|
|
|
2259
2289
|
sleep(ms) {
|
|
2260
2290
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2261
2291
|
}
|
|
2262
|
-
log(...
|
|
2292
|
+
log(...args) {
|
|
2293
|
+
if (this.config.debug) console.log("[Paywallo:Http]", ...args);
|
|
2263
2294
|
}
|
|
2264
2295
|
setDebug(debug) {
|
|
2265
2296
|
this.config.debug = debug;
|
|
@@ -2285,8 +2316,6 @@ var NetworkMonitorClass = class {
|
|
|
2285
2316
|
this.config = DEFAULT_NETWORK_CONFIG;
|
|
2286
2317
|
this.listeners = /* @__PURE__ */ new Set();
|
|
2287
2318
|
this.currentState = "unknown";
|
|
2288
|
-
this.netInfoModule = null;
|
|
2289
|
-
this.netInfoSubscription = null;
|
|
2290
2319
|
this.appStateSubscription = null;
|
|
2291
2320
|
this.initialized = false;
|
|
2292
2321
|
this.checkIntervalId = null;
|
|
@@ -2302,13 +2331,6 @@ var NetworkMonitorClass = class {
|
|
|
2302
2331
|
void this.setupFallbackDetection();
|
|
2303
2332
|
this.setupAppStateListener();
|
|
2304
2333
|
}
|
|
2305
|
-
setupNetInfoListener() {
|
|
2306
|
-
if (!this.netInfoModule) return;
|
|
2307
|
-
this.netInfoSubscription = this.netInfoModule.addEventListener((state) => {
|
|
2308
|
-
const newState = this.netInfoStateToNetworkState(state);
|
|
2309
|
-
this.updateState(newState);
|
|
2310
|
-
});
|
|
2311
|
-
}
|
|
2312
2334
|
async setupFallbackDetection() {
|
|
2313
2335
|
await this.checkConnectivity();
|
|
2314
2336
|
this.checkIntervalId = setInterval(() => {
|
|
@@ -2336,15 +2358,6 @@ var NetworkMonitorClass = class {
|
|
|
2336
2358
|
this.updateState("offline");
|
|
2337
2359
|
}
|
|
2338
2360
|
}
|
|
2339
|
-
netInfoStateToNetworkState(state) {
|
|
2340
|
-
if (state.isConnected === null) {
|
|
2341
|
-
return "unknown";
|
|
2342
|
-
}
|
|
2343
|
-
if (!state.isConnected) {
|
|
2344
|
-
return "offline";
|
|
2345
|
-
}
|
|
2346
|
-
return "online";
|
|
2347
|
-
}
|
|
2348
2361
|
updateState(newState) {
|
|
2349
2362
|
const previousState = this.currentState;
|
|
2350
2363
|
if (previousState === newState) {
|
|
@@ -2387,10 +2400,6 @@ var NetworkMonitorClass = class {
|
|
|
2387
2400
|
return this.currentState;
|
|
2388
2401
|
}
|
|
2389
2402
|
dispose() {
|
|
2390
|
-
if (this.netInfoSubscription) {
|
|
2391
|
-
this.netInfoSubscription();
|
|
2392
|
-
this.netInfoSubscription = null;
|
|
2393
|
-
}
|
|
2394
2403
|
if (this.appStateSubscription) {
|
|
2395
2404
|
this.appStateSubscription.remove();
|
|
2396
2405
|
this.appStateSubscription = null;
|
|
@@ -2403,7 +2412,8 @@ var NetworkMonitorClass = class {
|
|
|
2403
2412
|
this.initialized = false;
|
|
2404
2413
|
this.currentState = "unknown";
|
|
2405
2414
|
}
|
|
2406
|
-
log(...
|
|
2415
|
+
log(...args) {
|
|
2416
|
+
if (this.config.debug) console.log("[Paywallo:Network]", ...args);
|
|
2407
2417
|
}
|
|
2408
2418
|
setDebug(debug) {
|
|
2409
2419
|
this.config.debug = debug;
|
|
@@ -2413,6 +2423,7 @@ var networkMonitor = new NetworkMonitorClass();
|
|
|
2413
2423
|
|
|
2414
2424
|
// src/core/queue/OfflineQueue.ts
|
|
2415
2425
|
var import_async_storage2 = __toESM(require("@react-native-async-storage/async-storage"));
|
|
2426
|
+
init_uuid();
|
|
2416
2427
|
|
|
2417
2428
|
// src/core/queue/deduplication.ts
|
|
2418
2429
|
function normalizeForComparison(obj) {
|
|
@@ -2650,7 +2661,8 @@ var OfflineQueueClass = class {
|
|
|
2650
2661
|
}
|
|
2651
2662
|
}
|
|
2652
2663
|
}
|
|
2653
|
-
log(...
|
|
2664
|
+
log(...args) {
|
|
2665
|
+
if (this.config.debug) console.log("[Paywallo:Queue]", ...args);
|
|
2654
2666
|
}
|
|
2655
2667
|
setDebug(debug) {
|
|
2656
2668
|
this.config.debug = debug;
|
|
@@ -2792,7 +2804,8 @@ var QueueProcessorClass = class {
|
|
|
2792
2804
|
this.httpClient = null;
|
|
2793
2805
|
this.initialized = false;
|
|
2794
2806
|
}
|
|
2795
|
-
log(...
|
|
2807
|
+
log(...args) {
|
|
2808
|
+
if (this.config.debug) console.log("[Paywallo:QueueProcessor]", ...args);
|
|
2796
2809
|
}
|
|
2797
2810
|
setDebug(debug) {
|
|
2798
2811
|
this.config.debug = debug;
|
|
@@ -2874,13 +2887,12 @@ var ApiCache = class {
|
|
|
2874
2887
|
};
|
|
2875
2888
|
|
|
2876
2889
|
// src/core/ApiClient.ts
|
|
2877
|
-
var SDK_VERSION = "1.
|
|
2878
|
-
var DEFAULT_BASE_URL = "https://panel.lucasqueiroga.shop";
|
|
2890
|
+
var SDK_VERSION = "1.4.1";
|
|
2879
2891
|
var _ApiClient = class _ApiClient {
|
|
2880
|
-
constructor(appKey, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2892
|
+
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2881
2893
|
this.cache = new ApiCache();
|
|
2882
2894
|
this.appKey = appKey;
|
|
2883
|
-
this.baseUrl =
|
|
2895
|
+
this.baseUrl = apiUrl;
|
|
2884
2896
|
this.webUrl = deriveWebUrl(this.baseUrl);
|
|
2885
2897
|
this.debug = debug;
|
|
2886
2898
|
this.environment = environment;
|
|
@@ -2933,7 +2945,8 @@ var _ApiClient = class _ApiClient {
|
|
|
2933
2945
|
sdkVersion: SDK_VERSION,
|
|
2934
2946
|
platform: import_react_native9.Platform.OS
|
|
2935
2947
|
}, true);
|
|
2936
|
-
} catch {
|
|
2948
|
+
} catch (err) {
|
|
2949
|
+
if (this.debug) console.warn("[Paywallo:ApiClient] reportError failed", err);
|
|
2937
2950
|
}
|
|
2938
2951
|
}
|
|
2939
2952
|
async trackEvent(eventName, distinctId, properties, timestamp) {
|
|
@@ -2973,6 +2986,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2973
2986
|
try {
|
|
2974
2987
|
const res = await this.get(`/api/v1/flags/${flagKey}?distinctId=${encodeURIComponent(distinctId)}`);
|
|
2975
2988
|
if (res.status === 404) {
|
|
2989
|
+
this.log("Flag not found (404):", flagKey);
|
|
2976
2990
|
const v = { variant: null };
|
|
2977
2991
|
this.cache.setVariant(key, v, this.cache.nullTTL);
|
|
2978
2992
|
return v;
|
|
@@ -2999,6 +3013,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2999
3013
|
try {
|
|
3000
3014
|
const res = await this.get(`/api/v1/paywalls/${placement}`);
|
|
3001
3015
|
if (res.status === 404) {
|
|
3016
|
+
this.log("Paywall not found (404):", placement);
|
|
3002
3017
|
this.cache.setPaywall(placement, null, this.cache.nullTTL);
|
|
3003
3018
|
return null;
|
|
3004
3019
|
}
|
|
@@ -3050,6 +3065,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3050
3065
|
try {
|
|
3051
3066
|
const res = await this.get(`/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
3052
3067
|
if (res.status === 404) {
|
|
3068
|
+
this.log("Primary campaign not found (404)");
|
|
3053
3069
|
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
3054
3070
|
return null;
|
|
3055
3071
|
}
|
|
@@ -3100,7 +3116,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3100
3116
|
headers: { "X-App-Key": this.appKey, "x-distinct-id": distinctId }
|
|
3101
3117
|
});
|
|
3102
3118
|
if (!res.ok) {
|
|
3103
|
-
this.log("
|
|
3119
|
+
this.log("evaluateFlags failed:", res.status, keys);
|
|
3104
3120
|
return {};
|
|
3105
3121
|
}
|
|
3106
3122
|
const raw = res.data;
|
|
@@ -3165,7 +3181,8 @@ var _ApiClient = class _ApiClient {
|
|
|
3165
3181
|
try {
|
|
3166
3182
|
const value = JSON.stringify({ variant: flag.variant, payload: flag.payload, cachedAt: Date.now() });
|
|
3167
3183
|
await secureStorage.set(`flag:${flagKey}:${distinctId}`, value);
|
|
3168
|
-
} catch {
|
|
3184
|
+
} catch (err) {
|
|
3185
|
+
this.log("writeFlagToStorage failed", err);
|
|
3169
3186
|
}
|
|
3170
3187
|
}
|
|
3171
3188
|
async postWithQueue(url, payload, label) {
|
|
@@ -3186,7 +3203,8 @@ var _ApiClient = class _ApiClient {
|
|
|
3186
3203
|
throw error;
|
|
3187
3204
|
}
|
|
3188
3205
|
}
|
|
3189
|
-
log(...
|
|
3206
|
+
log(...args) {
|
|
3207
|
+
if (this.debug) console.log("[Paywallo:ApiClient]", ...args);
|
|
3190
3208
|
}
|
|
3191
3209
|
};
|
|
3192
3210
|
_ApiClient.FLAG_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -3354,43 +3372,67 @@ var AdvertisingIdManager = class {
|
|
|
3354
3372
|
}
|
|
3355
3373
|
};
|
|
3356
3374
|
|
|
3357
|
-
// src/domains/identity/
|
|
3375
|
+
// src/domains/identity/InstallTracker.ts
|
|
3376
|
+
var import_react_native14 = require("react-native");
|
|
3377
|
+
var import_async_storage3 = __toESM(require("@react-native-async-storage/async-storage"));
|
|
3378
|
+
var import_react_native_device_info2 = __toESM(require("react-native-device-info"));
|
|
3379
|
+
|
|
3380
|
+
// src/domains/identity/MetaBridge.ts
|
|
3381
|
+
var import_react_native11 = require("react-native");
|
|
3358
3382
|
var TIMEOUT_MS = 2e3;
|
|
3359
|
-
var
|
|
3360
|
-
|
|
3383
|
+
var NativeBridge = import_react_native11.NativeModules.PaywalloFBBridge ?? null;
|
|
3384
|
+
var MetaBridge = class {
|
|
3385
|
+
async getAnonymousID() {
|
|
3386
|
+
if (!NativeBridge) return null;
|
|
3361
3387
|
try {
|
|
3362
3388
|
let timerId;
|
|
3363
|
-
const
|
|
3389
|
+
const timeout = new Promise((resolve) => {
|
|
3364
3390
|
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
3365
3391
|
});
|
|
3366
|
-
const result = await Promise.race([
|
|
3392
|
+
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
3367
3393
|
clearTimeout(timerId);
|
|
3368
3394
|
return result;
|
|
3369
3395
|
} catch {
|
|
3370
3396
|
return null;
|
|
3371
3397
|
}
|
|
3372
3398
|
}
|
|
3373
|
-
async
|
|
3399
|
+
async logEvent(name, params = {}) {
|
|
3400
|
+
if (!NativeBridge) return;
|
|
3374
3401
|
try {
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3402
|
+
await NativeBridge.logEvent(name, params);
|
|
3403
|
+
} catch {
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
async logPurchase(amount, currency, params = {}) {
|
|
3407
|
+
if (!NativeBridge) return;
|
|
3408
|
+
try {
|
|
3409
|
+
await NativeBridge.logPurchase(amount, currency, params);
|
|
3410
|
+
} catch {
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
setUserID(userId) {
|
|
3414
|
+
if (!NativeBridge) return;
|
|
3415
|
+
try {
|
|
3416
|
+
NativeBridge.setUserID(userId);
|
|
3417
|
+
} catch {
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
flush() {
|
|
3421
|
+
if (!NativeBridge) return;
|
|
3422
|
+
try {
|
|
3423
|
+
NativeBridge.flush();
|
|
3378
3424
|
} catch {
|
|
3379
|
-
return null;
|
|
3380
3425
|
}
|
|
3381
3426
|
}
|
|
3382
3427
|
};
|
|
3383
|
-
var
|
|
3384
|
-
|
|
3385
|
-
// src/domains/identity/InstallTracker.ts
|
|
3386
|
-
var import_react_native13 = require("react-native");
|
|
3428
|
+
var metaBridge = new MetaBridge();
|
|
3387
3429
|
|
|
3388
3430
|
// src/domains/identity/InstallReferrerManager.ts
|
|
3389
|
-
var
|
|
3431
|
+
var import_react_native12 = require("react-native");
|
|
3390
3432
|
var REFERRER_TIMEOUT_MS = 5e3;
|
|
3391
3433
|
var InstallReferrerManager = class {
|
|
3392
3434
|
async getReferrer() {
|
|
3393
|
-
if (
|
|
3435
|
+
if (import_react_native12.Platform.OS !== "android") {
|
|
3394
3436
|
return this.emptyResult();
|
|
3395
3437
|
}
|
|
3396
3438
|
let timerId;
|
|
@@ -3450,7 +3492,8 @@ var InstallReferrerManager = class {
|
|
|
3450
3492
|
var installReferrerManager = new InstallReferrerManager();
|
|
3451
3493
|
|
|
3452
3494
|
// src/domains/session/SessionManager.ts
|
|
3453
|
-
var
|
|
3495
|
+
var import_react_native13 = require("react-native");
|
|
3496
|
+
init_uuid();
|
|
3454
3497
|
|
|
3455
3498
|
// src/domains/session/sessionTracking.ts
|
|
3456
3499
|
async function trackSessionStart(apiClient, sessionId, sessionStartedAt) {
|
|
@@ -3618,7 +3661,7 @@ var SessionManager = class {
|
|
|
3618
3661
|
if (this.appStateSubscription) {
|
|
3619
3662
|
this.appStateSubscription.remove();
|
|
3620
3663
|
}
|
|
3621
|
-
this.appStateSubscription =
|
|
3664
|
+
this.appStateSubscription = import_react_native13.AppState.addEventListener("change", this.handleAppStateChange);
|
|
3622
3665
|
}
|
|
3623
3666
|
async handleForeground() {
|
|
3624
3667
|
if (this.backgroundTimestamp) {
|
|
@@ -3679,7 +3722,8 @@ var SessionManager = class {
|
|
|
3679
3722
|
);
|
|
3680
3723
|
}
|
|
3681
3724
|
}
|
|
3682
|
-
log(...
|
|
3725
|
+
log(...args) {
|
|
3726
|
+
if (this.debug) console.log("[Paywallo:Session]", ...args);
|
|
3683
3727
|
}
|
|
3684
3728
|
};
|
|
3685
3729
|
var sessionManager = new SessionManager();
|
|
@@ -3692,12 +3736,11 @@ var InstallTracker = class {
|
|
|
3692
3736
|
}
|
|
3693
3737
|
async trackIfNeeded(apiClient, requestATT = false) {
|
|
3694
3738
|
const storage = new SecureStorage(this.debug);
|
|
3695
|
-
const alreadyTracked = await storage.get("install_tracked");
|
|
3739
|
+
const alreadyTracked = await storage.get("@panel:install_tracked");
|
|
3696
3740
|
if (alreadyTracked) return;
|
|
3697
3741
|
let fallbackTracked = null;
|
|
3698
3742
|
try {
|
|
3699
|
-
|
|
3700
|
-
fallbackTracked = await AsyncStorage3.getItem("@paywallo:install_tracked");
|
|
3743
|
+
fallbackTracked = await import_async_storage3.default.getItem("@paywallo:install_tracked");
|
|
3701
3744
|
} catch {
|
|
3702
3745
|
}
|
|
3703
3746
|
if (fallbackTracked) return;
|
|
@@ -3705,16 +3748,10 @@ var InstallTracker = class {
|
|
|
3705
3748
|
const sessionId = sessionManager.getSessionId();
|
|
3706
3749
|
const installedAt = Date.now();
|
|
3707
3750
|
if (!distinctId) return;
|
|
3708
|
-
|
|
3709
|
-
try {
|
|
3710
|
-
const mod = await import("react-native-device-info");
|
|
3711
|
-
deviceInfo = mod.default;
|
|
3712
|
-
} catch {
|
|
3713
|
-
deviceInfo = null;
|
|
3714
|
-
}
|
|
3751
|
+
const deviceInfo = import_react_native_device_info2.default;
|
|
3715
3752
|
let deviceData = {};
|
|
3716
3753
|
try {
|
|
3717
|
-
const screen =
|
|
3754
|
+
const screen = import_react_native14.Dimensions.get("screen");
|
|
3718
3755
|
const screenWidth = Math.round(screen.width ?? 0);
|
|
3719
3756
|
const screenHeight = Math.round(screen.height ?? 0);
|
|
3720
3757
|
const locale = Intl.DateTimeFormat().resolvedOptions().locale ?? "unknown";
|
|
@@ -3723,6 +3760,38 @@ var InstallTracker = class {
|
|
|
3723
3760
|
const osVersion = deviceInfo?.getSystemVersion() || "unknown";
|
|
3724
3761
|
const appVersion = deviceInfo?.getVersion() || "unknown";
|
|
3725
3762
|
const buildNumber = deviceInfo?.getBuildNumber() || "0";
|
|
3763
|
+
let carrier = "unknown";
|
|
3764
|
+
try {
|
|
3765
|
+
carrier = await deviceInfo?.getCarrier?.() ?? "unknown";
|
|
3766
|
+
} catch {
|
|
3767
|
+
}
|
|
3768
|
+
let totalDisk = 0;
|
|
3769
|
+
try {
|
|
3770
|
+
totalDisk = Number(await deviceInfo?.getTotalDiskCapacity?.()) || 0;
|
|
3771
|
+
} catch {
|
|
3772
|
+
}
|
|
3773
|
+
let freeDisk = 0;
|
|
3774
|
+
try {
|
|
3775
|
+
freeDisk = Number(await deviceInfo?.getFreeDiskStorage?.()) || 0;
|
|
3776
|
+
} catch {
|
|
3777
|
+
}
|
|
3778
|
+
let totalRam = 0;
|
|
3779
|
+
try {
|
|
3780
|
+
totalRam = Number(await deviceInfo?.getTotalMemory?.()) || 0;
|
|
3781
|
+
} catch {
|
|
3782
|
+
}
|
|
3783
|
+
let brand = "unknown";
|
|
3784
|
+
try {
|
|
3785
|
+
brand = deviceInfo?.getBrand?.() ?? "unknown";
|
|
3786
|
+
} catch {
|
|
3787
|
+
}
|
|
3788
|
+
let installerPackage = null;
|
|
3789
|
+
try {
|
|
3790
|
+
if (import_react_native14.Platform.OS === "android") {
|
|
3791
|
+
installerPackage = await deviceInfo?.getInstallerPackageName?.() ?? null;
|
|
3792
|
+
}
|
|
3793
|
+
} catch {
|
|
3794
|
+
}
|
|
3726
3795
|
deviceData = {
|
|
3727
3796
|
deviceModel,
|
|
3728
3797
|
osVersion,
|
|
@@ -3731,22 +3800,40 @@ var InstallTracker = class {
|
|
|
3731
3800
|
...screenWidth > 0 && { screenWidth },
|
|
3732
3801
|
...screenHeight > 0 && { screenHeight },
|
|
3733
3802
|
timezone,
|
|
3734
|
-
locale
|
|
3803
|
+
locale,
|
|
3804
|
+
...carrier !== "unknown" && { carrier },
|
|
3805
|
+
...totalDisk > 0 && { totalDisk },
|
|
3806
|
+
...freeDisk > 0 && { freeDisk },
|
|
3807
|
+
...totalRam > 0 && { totalRam },
|
|
3808
|
+
...brand !== "unknown" && { brand },
|
|
3809
|
+
...installerPackage && { installerPackage }
|
|
3735
3810
|
};
|
|
3736
3811
|
} catch {
|
|
3737
3812
|
}
|
|
3738
3813
|
const [fbAnonId, referrer, adIds] = await Promise.all([
|
|
3739
|
-
|
|
3814
|
+
metaBridge.getAnonymousID(),
|
|
3740
3815
|
installReferrerManager.getReferrer(),
|
|
3741
3816
|
this.advertisingIdManager.collect(requestATT)
|
|
3742
3817
|
]);
|
|
3818
|
+
let effectiveAnonId = fbAnonId;
|
|
3819
|
+
if (!effectiveAnonId) {
|
|
3820
|
+
const stored = await storage.get("@panel:anon_id");
|
|
3821
|
+
if (stored) {
|
|
3822
|
+
effectiveAnonId = stored;
|
|
3823
|
+
} else {
|
|
3824
|
+
const { generateUUID: generateUUID2 } = await Promise.resolve().then(() => (init_uuid(), uuid_exports));
|
|
3825
|
+
effectiveAnonId = `PW_${generateUUID2()}`;
|
|
3826
|
+
await storage.set("@panel:anon_id", effectiveAnonId).catch(() => {
|
|
3827
|
+
});
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3743
3830
|
try {
|
|
3744
3831
|
await apiClient.trackEvent("$app_installed", distinctId, {
|
|
3745
3832
|
installedAt,
|
|
3746
|
-
platform:
|
|
3833
|
+
platform: import_react_native14.Platform.OS,
|
|
3747
3834
|
...sessionId && { sessionId },
|
|
3748
3835
|
...deviceData,
|
|
3749
|
-
...
|
|
3836
|
+
...effectiveAnonId && { fbAnonId: effectiveAnonId },
|
|
3750
3837
|
...referrer.rawReferrer && { installReferrer: referrer.rawReferrer },
|
|
3751
3838
|
...referrer.trackingId && { referrerTrackingId: referrer.trackingId },
|
|
3752
3839
|
...referrer.fbclid && { referrerFbclid: referrer.fbclid },
|
|
@@ -3758,15 +3845,49 @@ var InstallTracker = class {
|
|
|
3758
3845
|
...adIds.gaid && { gaid: adIds.gaid },
|
|
3759
3846
|
attStatus: adIds.attStatus
|
|
3760
3847
|
});
|
|
3761
|
-
|
|
3848
|
+
if (import_react_native14.Platform.OS === "ios") {
|
|
3849
|
+
void this.callDeferredMatch(apiClient, deviceData, adIds, effectiveAnonId).catch(() => {
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3852
|
+
await storage.set("@panel:install_tracked", String(installedAt));
|
|
3762
3853
|
try {
|
|
3763
|
-
|
|
3764
|
-
await AsyncStorage3.setItem("@paywallo:install_tracked", String(installedAt));
|
|
3854
|
+
await import_async_storage3.default.setItem("@paywallo:install_tracked", String(installedAt));
|
|
3765
3855
|
} catch {
|
|
3766
3856
|
}
|
|
3767
3857
|
} catch {
|
|
3768
3858
|
}
|
|
3769
3859
|
}
|
|
3860
|
+
async callDeferredMatch(apiClient, deviceData, adIds, anonId) {
|
|
3861
|
+
const storage = new SecureStorage(this.debug);
|
|
3862
|
+
const alreadyMatched = await storage.get("@panel:deferred_match_done");
|
|
3863
|
+
if (alreadyMatched) return;
|
|
3864
|
+
const controller = new AbortController();
|
|
3865
|
+
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
3866
|
+
try {
|
|
3867
|
+
const baseUrl = apiClient.getBaseUrl();
|
|
3868
|
+
const appKey = apiClient.appKey;
|
|
3869
|
+
await fetch(`${baseUrl}/api/v1/attribution/deferred-match`, {
|
|
3870
|
+
method: "POST",
|
|
3871
|
+
headers: { "Content-Type": "application/json", "X-App-Key": appKey },
|
|
3872
|
+
body: JSON.stringify({
|
|
3873
|
+
idfv: adIds.idfv,
|
|
3874
|
+
deviceModel: deviceData.deviceModel,
|
|
3875
|
+
osVersion: deviceData.osVersion,
|
|
3876
|
+
screenWidth: deviceData.screenWidth,
|
|
3877
|
+
screenHeight: deviceData.screenHeight,
|
|
3878
|
+
timezone: deviceData.timezone,
|
|
3879
|
+
locale: deviceData.locale,
|
|
3880
|
+
fbAnonId: anonId
|
|
3881
|
+
}),
|
|
3882
|
+
signal: controller.signal
|
|
3883
|
+
});
|
|
3884
|
+
await storage.set("@panel:deferred_match_done", "1").catch(() => {
|
|
3885
|
+
});
|
|
3886
|
+
} catch {
|
|
3887
|
+
} finally {
|
|
3888
|
+
clearTimeout(timer);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3770
3891
|
};
|
|
3771
3892
|
|
|
3772
3893
|
// src/core/PaywalloClient.ts
|
|
@@ -3858,9 +3979,12 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3858
3979
|
this.networkCleanup = networkMonitor.addListener((state) => {
|
|
3859
3980
|
if (state !== "online") return;
|
|
3860
3981
|
if (this.config && this.apiClient) return;
|
|
3982
|
+
if (this.initPromise) return;
|
|
3861
3983
|
this.initPromise = this.initWithRetry(config);
|
|
3862
3984
|
this.initPromise.catch(() => {
|
|
3863
3985
|
this.reportInitFailure(config, null, "NETWORK_RECOVERY_FAILED");
|
|
3986
|
+
}).finally(() => {
|
|
3987
|
+
if (!this.isReady()) this.initPromise = null;
|
|
3864
3988
|
});
|
|
3865
3989
|
});
|
|
3866
3990
|
}
|
|
@@ -3872,12 +3996,13 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3872
3996
|
}
|
|
3873
3997
|
reportInitFailure(config, error, reason) {
|
|
3874
3998
|
try {
|
|
3875
|
-
const tempClient = new ApiClient(config.appKey, config.debug);
|
|
3999
|
+
const tempClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug);
|
|
3876
4000
|
void tempClient.reportError("INIT_FAILED", reason, {
|
|
3877
4001
|
attempts: this.initAttempts,
|
|
3878
4002
|
error: error instanceof Error ? error.message : String(error)
|
|
3879
4003
|
});
|
|
3880
|
-
} catch {
|
|
4004
|
+
} catch (err) {
|
|
4005
|
+
if (config.debug) console.warn("[Paywallo] reportInitFailure error", err);
|
|
3881
4006
|
}
|
|
3882
4007
|
}
|
|
3883
4008
|
reportInitSuccess(config, attempts) {
|
|
@@ -3885,7 +4010,8 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3885
4010
|
if (this.apiClient) {
|
|
3886
4011
|
void this.apiClient.reportError("INIT_RECOVERED", `Succeeded after ${attempts} retries`, { attempts });
|
|
3887
4012
|
}
|
|
3888
|
-
} catch {
|
|
4013
|
+
} catch (err) {
|
|
4014
|
+
if (config.debug) console.warn("[Paywallo] reportInitSuccess error", err);
|
|
3889
4015
|
}
|
|
3890
4016
|
}
|
|
3891
4017
|
async resolveSessionFlags(keys, apiClient, distinctId) {
|
|
@@ -3910,7 +4036,7 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3910
4036
|
() => offlineQueue.clearItemsWithInvalidAppKey(config.appKey)
|
|
3911
4037
|
)
|
|
3912
4038
|
]);
|
|
3913
|
-
this.apiClient = new ApiClient(config.appKey, config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
4039
|
+
this.apiClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
3914
4040
|
queueProcessor.initialize(this.apiClient.getHttpClient(), { debug: config.debug });
|
|
3915
4041
|
affiliateManager.initialize(this.apiClient, config.debug);
|
|
3916
4042
|
subscriptionManager.init({
|
|
@@ -3964,18 +4090,21 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3964
4090
|
}
|
|
3965
4091
|
async identify(options) {
|
|
3966
4092
|
this.ensureInitialized();
|
|
4093
|
+
if (this.config?.debug) console.info("[Paywallo IDENTIFY]", options);
|
|
3967
4094
|
await identityManager.identify(options);
|
|
3968
4095
|
}
|
|
3969
4096
|
async track(eventName, options) {
|
|
3970
4097
|
const apiClient = this.getApiClientOrThrow();
|
|
3971
4098
|
const distinctId = identityManager.getDistinctId();
|
|
3972
4099
|
if (!distinctId) {
|
|
4100
|
+
if (this.config?.debug) console.info(`[Paywallo TRACK] ${eventName} skipped (no distinctId)`);
|
|
3973
4101
|
return;
|
|
3974
4102
|
}
|
|
3975
4103
|
if (!isValidEventName(eventName)) {
|
|
3976
4104
|
const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
|
|
3977
4105
|
throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
|
|
3978
4106
|
}
|
|
4107
|
+
if (this.config?.debug && eventName.startsWith("$purchase")) console.info(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
3979
4108
|
const sessionId = sessionManager.getSessionId();
|
|
3980
4109
|
await apiClient.trackEvent(eventName, distinctId, {
|
|
3981
4110
|
...identityManager.getProperties(),
|
|
@@ -3996,14 +4125,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3996
4125
|
const now = Date.now();
|
|
3997
4126
|
const timeOnPreviousStep = this.lastOnboardingStepTimestamp !== null ? Math.round((now - this.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
3998
4127
|
this.lastOnboardingStepTimestamp = now;
|
|
3999
|
-
const sessionId = sessionManager.getSessionId();
|
|
4000
4128
|
await apiClient.trackEvent("$onboarding_step", distinctId, {
|
|
4001
|
-
...identityManager.getProperties(),
|
|
4002
4129
|
stepIndex: index,
|
|
4003
4130
|
stepName: name,
|
|
4004
|
-
|
|
4005
|
-
timeOnPreviousStep,
|
|
4006
|
-
...sessionId && { sessionId }
|
|
4131
|
+
timeOnPreviousStep
|
|
4007
4132
|
});
|
|
4008
4133
|
}
|
|
4009
4134
|
async coreAction(actionName) {
|
|
@@ -4038,10 +4163,14 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4038
4163
|
try {
|
|
4039
4164
|
const distinctId = identityManager.getDistinctId();
|
|
4040
4165
|
if (!distinctId) {
|
|
4166
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192 null (no distinctId)`);
|
|
4041
4167
|
return { variant: null };
|
|
4042
4168
|
}
|
|
4043
|
-
|
|
4169
|
+
const result = await this.getApiClientOrThrow().getVariant(flagKey, distinctId);
|
|
4170
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192`, result.variant);
|
|
4171
|
+
return result;
|
|
4044
4172
|
} catch (error) {
|
|
4173
|
+
if (this.config?.debug) console.warn(`[Paywallo FLAG] ${flagKey} \u2192 error`, error);
|
|
4045
4174
|
if (this.apiClient) void this.apiClient.reportError("GET_VARIANT_FAILED", error instanceof Error ? error.message : String(error));
|
|
4046
4175
|
return { variant: null };
|
|
4047
4176
|
}
|
|
@@ -4074,21 +4203,34 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4074
4203
|
}
|
|
4075
4204
|
async presentCampaign(placement, context) {
|
|
4076
4205
|
this.ensureInitialized();
|
|
4077
|
-
|
|
4206
|
+
if (this.config?.debug) console.info(`[Paywallo CAMPAIGN] presenting ${placement}`);
|
|
4207
|
+
const result = await campaignGateService.presentCampaign(this.getApiClientOrThrow(), placement, () => this.hasActiveSubscription(), this.paywallPresenter, this.campaignPresenter, context);
|
|
4208
|
+
if (this.config?.debug) {
|
|
4209
|
+
if (result.error) console.warn(`[Paywallo CAMPAIGN] ${placement} error:`, result.error.message);
|
|
4210
|
+
else console.info(`[Paywallo CAMPAIGN] ${placement} result:`, { purchased: result.purchased, cancelled: result.cancelled, restored: result.restored, skippedReason: result.skippedReason });
|
|
4211
|
+
}
|
|
4212
|
+
return result;
|
|
4078
4213
|
}
|
|
4079
4214
|
async hasActiveSubscription() {
|
|
4080
4215
|
this.ensureInitialized();
|
|
4081
4216
|
try {
|
|
4082
4217
|
if (this.activeChecker) {
|
|
4083
|
-
|
|
4218
|
+
const result = await this.activeChecker();
|
|
4219
|
+
const isActive2 = result === true;
|
|
4220
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (checker):", isActive2);
|
|
4221
|
+
return isActive2;
|
|
4084
4222
|
}
|
|
4085
4223
|
const distinctId = identityManager.getDistinctId();
|
|
4086
4224
|
if (!distinctId || !this.apiClient) {
|
|
4225
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription: false (no distinctId/apiClient)");
|
|
4087
4226
|
return false;
|
|
4088
4227
|
}
|
|
4089
4228
|
const status = await this.apiClient.getSubscriptionStatus(distinctId);
|
|
4090
|
-
|
|
4229
|
+
const isActive = status.hasActiveSubscription === true;
|
|
4230
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (server):", isActive);
|
|
4231
|
+
return isActive;
|
|
4091
4232
|
} catch (error) {
|
|
4233
|
+
if (this.config?.debug) console.warn("[Paywallo SUB] hasActiveSubscription error", error);
|
|
4092
4234
|
if (this.apiClient) void this.apiClient.reportError("SUBSCRIPTION_CHECK_FAILED", error instanceof Error ? error.message : "hasActiveSubscription failed");
|
|
4093
4235
|
return false;
|
|
4094
4236
|
}
|
|
@@ -4109,7 +4251,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4109
4251
|
async restorePurchases() {
|
|
4110
4252
|
this.ensureInitialized();
|
|
4111
4253
|
if (!this.restoreHandler) throw new PaywallError(PAYWALL_ERROR_CODES.NOT_INITIALIZED, "PaywalloProvider not mounted. Wrap your app with <PaywalloProvider>");
|
|
4112
|
-
|
|
4254
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] starting");
|
|
4255
|
+
const result = await this.restoreHandler();
|
|
4256
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] result:", { success: result.success, restoredProducts: result.restoredProducts?.length ?? 0 });
|
|
4257
|
+
return result;
|
|
4113
4258
|
}
|
|
4114
4259
|
async reset() {
|
|
4115
4260
|
await identityManager.reset();
|
|
@@ -4395,9 +4540,7 @@ function usePurchase() {
|
|
|
4395
4540
|
setError(null);
|
|
4396
4541
|
try {
|
|
4397
4542
|
const iapService = getIAPService();
|
|
4398
|
-
const result = await iapService.purchase(productId
|
|
4399
|
-
onValidating: () => setState("validating")
|
|
4400
|
-
});
|
|
4543
|
+
const result = await iapService.purchase(productId);
|
|
4401
4544
|
if (result.success && result.purchase) {
|
|
4402
4545
|
setState("idle");
|
|
4403
4546
|
return {
|
|
@@ -4453,9 +4596,7 @@ function usePurchase() {
|
|
|
4453
4596
|
purchase,
|
|
4454
4597
|
restore,
|
|
4455
4598
|
error,
|
|
4456
|
-
|
|
4457
|
-
isPurchasing: state === "purchasing" || state === "validating",
|
|
4458
|
-
isValidating: state === "validating",
|
|
4599
|
+
isPurchasing: state === "purchasing",
|
|
4459
4600
|
isRestoring: state === "restoring"
|
|
4460
4601
|
};
|
|
4461
4602
|
}
|
|
@@ -4496,6 +4637,9 @@ function useSubscription() {
|
|
|
4496
4637
|
void subscriptionManager.getSubscriptionStatus().then((s) => {
|
|
4497
4638
|
setStatus(s);
|
|
4498
4639
|
setIsLoading(false);
|
|
4640
|
+
}).catch((err) => {
|
|
4641
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4642
|
+
setIsLoading(false);
|
|
4499
4643
|
});
|
|
4500
4644
|
const removeListener = subscriptionManager.addListener((newStatus) => {
|
|
4501
4645
|
setStatus(newStatus);
|
|
@@ -4517,7 +4661,7 @@ function useSubscription() {
|
|
|
4517
4661
|
|
|
4518
4662
|
// src/PaywalloProvider.tsx
|
|
4519
4663
|
var import_react18 = require("react");
|
|
4520
|
-
var
|
|
4664
|
+
var import_react_native15 = require("react-native");
|
|
4521
4665
|
|
|
4522
4666
|
// src/hooks/useCampaignPreload.ts
|
|
4523
4667
|
var import_react14 = require("react");
|
|
@@ -4675,7 +4819,8 @@ function useProductLoader() {
|
|
|
4675
4819
|
const map = /* @__PURE__ */ new Map();
|
|
4676
4820
|
for (const p of loaded) map.set(p.productId, p);
|
|
4677
4821
|
setProducts(map);
|
|
4678
|
-
} catch (
|
|
4822
|
+
} catch (err) {
|
|
4823
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] refreshProducts failed", err);
|
|
4679
4824
|
} finally {
|
|
4680
4825
|
setIsLoadingProducts(false);
|
|
4681
4826
|
}
|
|
@@ -4715,6 +4860,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4715
4860
|
clearPreloadedWebView();
|
|
4716
4861
|
resolvePreloadedPaywall({ presented: true, purchased: true, cancelled: false, restored: false });
|
|
4717
4862
|
} catch (error) {
|
|
4863
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] preloaded purchase failed", error);
|
|
4718
4864
|
setShowingPreloadedWebView(false);
|
|
4719
4865
|
clearPreloadedWebView();
|
|
4720
4866
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -4735,6 +4881,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4735
4881
|
clearPreloadedWebView();
|
|
4736
4882
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: true });
|
|
4737
4883
|
} catch (error) {
|
|
4884
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] preloaded restore failed", error);
|
|
4738
4885
|
setShowingPreloadedWebView(false);
|
|
4739
4886
|
clearPreloadedWebView();
|
|
4740
4887
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -4847,7 +4994,7 @@ function useSubscriptionSync() {
|
|
|
4847
4994
|
cacheRef.current = { data: sub, expiresAt: Date.now() + CACHE_TTL_MS2 };
|
|
4848
4995
|
setSubscription(sub);
|
|
4849
4996
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
4850
|
-
return status.hasActiveSubscription;
|
|
4997
|
+
return status.hasActiveSubscription === true;
|
|
4851
4998
|
} catch {
|
|
4852
4999
|
return await resolveOfflineFromCache(distinctId);
|
|
4853
5000
|
}
|
|
@@ -4903,8 +5050,8 @@ function PaywalloProvider({ children, config }) {
|
|
|
4903
5050
|
});
|
|
4904
5051
|
}, []);
|
|
4905
5052
|
const { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady: baseHandlePreloadedWebViewReady, handlePreloadedClose: baseHandlePreloadedClose, setShowingPreloadedWebView, presentedAtRef } = usePaywallPresenter(preloadedWebView, setPreloadedWebView);
|
|
4906
|
-
const SCREEN_HEIGHT3 = (0, import_react18.useMemo)(() =>
|
|
4907
|
-
const slideAnim = (0, import_react18.useRef)(new
|
|
5053
|
+
const SCREEN_HEIGHT3 = (0, import_react18.useMemo)(() => import_react_native15.Dimensions.get("window").height, []);
|
|
5054
|
+
const slideAnim = (0, import_react18.useRef)(new import_react_native15.Animated.Value(SCREEN_HEIGHT3)).current;
|
|
4908
5055
|
const handlePreloadedWebViewReady = (0, import_react18.useCallback)(() => {
|
|
4909
5056
|
if (PaywalloClient.getConfig()?.debug) {
|
|
4910
5057
|
console.info(`[Paywallo WEBVIEW] loaded \u2014 placement: ${preloadedWebView?.placement}`);
|
|
@@ -4913,7 +5060,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
4913
5060
|
}, [config?.debug, preloadedWebView?.placement, baseHandlePreloadedWebViewReady]);
|
|
4914
5061
|
const handlePreloadedClose = (0, import_react18.useCallback)(() => {
|
|
4915
5062
|
const placement = preloadedWebView?.placement;
|
|
4916
|
-
|
|
5063
|
+
import_react_native15.Animated.timing(slideAnim, { toValue: SCREEN_HEIGHT3, duration: 200, easing: import_react_native15.Easing.in(import_react_native15.Easing.cubic), useNativeDriver: true }).start(() => {
|
|
4917
5064
|
baseHandlePreloadedClose();
|
|
4918
5065
|
if (placement) triggerRepreload(placement);
|
|
4919
5066
|
});
|
|
@@ -5129,7 +5276,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
5129
5276
|
(0, import_react18.useLayoutEffect)(() => {
|
|
5130
5277
|
if (showingPreloadedWebView) {
|
|
5131
5278
|
slideAnim.setValue(SCREEN_HEIGHT3);
|
|
5132
|
-
|
|
5279
|
+
import_react_native15.Animated.timing(slideAnim, { toValue: 0, duration: 200, easing: import_react_native15.Easing.out(import_react_native15.Easing.cubic), useNativeDriver: true }).start();
|
|
5133
5280
|
}
|
|
5134
5281
|
}, [showingPreloadedWebView, slideAnim, SCREEN_HEIGHT3]);
|
|
5135
5282
|
const preloadStyle = [
|
|
@@ -5139,7 +5286,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
5139
5286
|
];
|
|
5140
5287
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(PaywalloContext.Provider, { value: contextValue, children: [
|
|
5141
5288
|
children,
|
|
5142
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaywallErrorBoundary, { children: !!preloadedWebView?.craftData && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5289
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaywallErrorBoundary, { children: !!preloadedWebView?.craftData && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native15.Animated.View, { style: preloadStyle, pointerEvents: showingPreloadedWebView ? "auto" : "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
5143
5290
|
PaywallWebView,
|
|
5144
5291
|
{
|
|
5145
5292
|
paywallId: preloadedWebView.paywallId,
|
|
@@ -5169,7 +5316,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
5169
5316
|
) })
|
|
5170
5317
|
] });
|
|
5171
5318
|
}
|
|
5172
|
-
var styles3 =
|
|
5319
|
+
var styles3 = import_react_native15.StyleSheet.create({
|
|
5173
5320
|
preloadOverlay: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "#ffffff" },
|
|
5174
5321
|
hidden: { zIndex: -1, opacity: 0, width: 1, height: 1, overflow: "hidden" },
|
|
5175
5322
|
visible: { zIndex: 9999, opacity: 1 }
|
|
@@ -5312,6 +5459,7 @@ var index_default = Paywallo;
|
|
|
5312
5459
|
IDENTITY_ERROR_CODES,
|
|
5313
5460
|
IdentityError,
|
|
5314
5461
|
IdentityManager,
|
|
5462
|
+
MetaBridge,
|
|
5315
5463
|
PAYWALL_ERROR_CODES,
|
|
5316
5464
|
PURCHASE_ERROR_CODES,
|
|
5317
5465
|
PaywallContext,
|
|
@@ -5338,6 +5486,7 @@ var index_default = Paywallo;
|
|
|
5338
5486
|
hasVariables,
|
|
5339
5487
|
identityManager,
|
|
5340
5488
|
initLocalization,
|
|
5489
|
+
metaBridge,
|
|
5341
5490
|
nativeStoreKit,
|
|
5342
5491
|
networkMonitor,
|
|
5343
5492
|
offlineQueue,
|