@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.mjs
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/utils/uuid.ts
|
|
12
|
+
var uuid_exports = {};
|
|
13
|
+
__export(uuid_exports, {
|
|
14
|
+
generateUUID: () => generateUUID
|
|
15
|
+
});
|
|
16
|
+
function generateUUID() {
|
|
17
|
+
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
18
|
+
return template.replace(/[xy]/g, (c) => {
|
|
19
|
+
const r = Math.random() * 16 | 0;
|
|
20
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
21
|
+
return v.toString(16);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
var init_uuid = __esm({
|
|
25
|
+
"src/utils/uuid.ts"() {
|
|
26
|
+
"use strict";
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
1
30
|
// src/errors/PaywalloError.ts
|
|
2
31
|
var PaywalloError = class extends Error {
|
|
3
32
|
constructor(domain, code, message) {
|
|
@@ -102,6 +131,9 @@ function createPurchaseError(code, message) {
|
|
|
102
131
|
// src/domains/iap/NativeStoreKit.ts
|
|
103
132
|
import { NativeModules, Platform } from "react-native";
|
|
104
133
|
|
|
134
|
+
// src/domains/identity/IdentityManager.ts
|
|
135
|
+
import DeviceInfo from "react-native-device-info";
|
|
136
|
+
|
|
105
137
|
// src/domains/identity/IdentityError.ts
|
|
106
138
|
var IdentityError = class extends PaywalloError {
|
|
107
139
|
constructor(code, message) {
|
|
@@ -117,29 +149,12 @@ var IDENTITY_ERROR_CODES = {
|
|
|
117
149
|
IDENTIFY_FAILED: "IDENTITY_IDENTIFY_FAILED"
|
|
118
150
|
};
|
|
119
151
|
|
|
120
|
-
// src/
|
|
121
|
-
|
|
122
|
-
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
123
|
-
return template.replace(/[xy]/g, (c) => {
|
|
124
|
-
const r = Math.random() * 16 | 0;
|
|
125
|
-
const v = c === "x" ? r : r & 3 | 8;
|
|
126
|
-
return v.toString(16);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
152
|
+
// src/domains/identity/IdentityManager.ts
|
|
153
|
+
init_uuid();
|
|
129
154
|
|
|
130
155
|
// src/core/storage/SecureStorage.ts
|
|
131
156
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
132
|
-
|
|
133
|
-
async function loadKeychain() {
|
|
134
|
-
if (_keychain !== void 0) return _keychain;
|
|
135
|
-
try {
|
|
136
|
-
const mod = await import("react-native-keychain");
|
|
137
|
-
_keychain = mod.default;
|
|
138
|
-
} catch {
|
|
139
|
-
_keychain = null;
|
|
140
|
-
}
|
|
141
|
-
return _keychain;
|
|
142
|
-
}
|
|
157
|
+
import Keychain from "react-native-keychain";
|
|
143
158
|
var KEYCHAIN_SERVICE_PREFIX = "com.paywallo.sdk.";
|
|
144
159
|
var SecureStorage = class {
|
|
145
160
|
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
|
@@ -183,13 +198,11 @@ var SecureStorage = class {
|
|
|
183
198
|
}
|
|
184
199
|
}
|
|
185
200
|
hasKeychainSupport() {
|
|
186
|
-
return
|
|
201
|
+
return true;
|
|
187
202
|
}
|
|
188
203
|
async getFromKeychain(key) {
|
|
189
|
-
const keychain = await loadKeychain();
|
|
190
|
-
if (!keychain) return null;
|
|
191
204
|
try {
|
|
192
|
-
const result = await
|
|
205
|
+
const result = await Keychain.getGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
193
206
|
if (result && result.password) {
|
|
194
207
|
return result.password;
|
|
195
208
|
}
|
|
@@ -199,20 +212,16 @@ var SecureStorage = class {
|
|
|
199
212
|
}
|
|
200
213
|
}
|
|
201
214
|
async setToKeychain(key, value) {
|
|
202
|
-
const keychain = await loadKeychain();
|
|
203
|
-
if (!keychain) return false;
|
|
204
215
|
try {
|
|
205
|
-
await
|
|
216
|
+
await Keychain.setGenericPassword("panel", value, { service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
206
217
|
return true;
|
|
207
218
|
} catch {
|
|
208
219
|
return false;
|
|
209
220
|
}
|
|
210
221
|
}
|
|
211
222
|
async removeFromKeychain(key) {
|
|
212
|
-
const keychain = await loadKeychain();
|
|
213
|
-
if (!keychain) return false;
|
|
214
223
|
try {
|
|
215
|
-
await
|
|
224
|
+
await Keychain.resetGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
|
|
216
225
|
return true;
|
|
217
226
|
} catch {
|
|
218
227
|
return false;
|
|
@@ -246,19 +255,8 @@ var IdentityManager = class {
|
|
|
246
255
|
this.secureStorage = new SecureStorage(debug);
|
|
247
256
|
await this.loadPersistedState();
|
|
248
257
|
if (!this.deviceId) {
|
|
249
|
-
let DeviceInfo = null;
|
|
250
|
-
try {
|
|
251
|
-
const mod = await import("react-native-device-info");
|
|
252
|
-
DeviceInfo = mod.default;
|
|
253
|
-
} catch {
|
|
254
|
-
DeviceInfo = null;
|
|
255
|
-
}
|
|
256
258
|
try {
|
|
257
|
-
|
|
258
|
-
this.deviceId = await DeviceInfo.getUniqueId();
|
|
259
|
-
} else {
|
|
260
|
-
this.deviceId = generateUUID();
|
|
261
|
-
}
|
|
259
|
+
this.deviceId = await DeviceInfo.getUniqueId();
|
|
262
260
|
} catch {
|
|
263
261
|
this.deviceId = generateUUID();
|
|
264
262
|
}
|
|
@@ -487,20 +485,41 @@ var nativeStoreKit = {
|
|
|
487
485
|
);
|
|
488
486
|
}
|
|
489
487
|
const distinctId = identityManager.getDistinctId();
|
|
490
|
-
const
|
|
491
|
-
if (!
|
|
492
|
-
|
|
488
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
489
|
+
if (distinctId && !uuidRegex.test(distinctId) && PaywalloClient.getConfig()?.debug) {
|
|
490
|
+
console.warn("[Paywallo] distinctId is not a valid UUID for appAccountToken:", distinctId);
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const result = await PaywalloStoreKitNative.purchase(productId, distinctId ?? null);
|
|
494
|
+
if (!result || result.pending) {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
return mapNativePurchase(result);
|
|
498
|
+
} catch (err) {
|
|
499
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
500
|
+
if (message.toLowerCase().includes("cancel")) {
|
|
501
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.USER_CANCELLED, message, true);
|
|
502
|
+
}
|
|
503
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, message);
|
|
493
504
|
}
|
|
494
|
-
return mapNativePurchase(result);
|
|
495
505
|
},
|
|
496
506
|
async finishTransaction(transactionId) {
|
|
497
507
|
if (!PaywalloStoreKitNative) return;
|
|
498
|
-
|
|
508
|
+
try {
|
|
509
|
+
await PaywalloStoreKitNative.finishTransaction(transactionId);
|
|
510
|
+
} catch (err) {
|
|
511
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction native error", err);
|
|
512
|
+
}
|
|
499
513
|
},
|
|
500
514
|
async getActiveTransactions() {
|
|
501
515
|
if (!PaywalloStoreKitNative) return [];
|
|
502
|
-
|
|
503
|
-
|
|
516
|
+
try {
|
|
517
|
+
const results = await PaywalloStoreKitNative.getActiveTransactions();
|
|
518
|
+
return results.map(mapNativePurchase);
|
|
519
|
+
} catch (err) {
|
|
520
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] getActiveTransactions failed", err);
|
|
521
|
+
return [];
|
|
522
|
+
}
|
|
504
523
|
}
|
|
505
524
|
};
|
|
506
525
|
|
|
@@ -543,7 +562,8 @@ var IAPService = class {
|
|
|
543
562
|
this.productsCache.set(product.productId, product);
|
|
544
563
|
}
|
|
545
564
|
return products;
|
|
546
|
-
} catch (
|
|
565
|
+
} catch (err) {
|
|
566
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] loadProducts failed", err);
|
|
547
567
|
return [];
|
|
548
568
|
}
|
|
549
569
|
}
|
|
@@ -588,7 +608,8 @@ var IAPService = class {
|
|
|
588
608
|
async finishTransaction(transactionId) {
|
|
589
609
|
try {
|
|
590
610
|
await nativeStoreKit.finishTransaction(transactionId);
|
|
591
|
-
} catch (
|
|
611
|
+
} catch (err) {
|
|
612
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction failed", err);
|
|
592
613
|
}
|
|
593
614
|
}
|
|
594
615
|
async purchase(productId, options) {
|
|
@@ -598,30 +619,25 @@ var IAPService = class {
|
|
|
598
619
|
error: new PurchaseError(PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE, "In-app purchases are not available on this device")
|
|
599
620
|
};
|
|
600
621
|
}
|
|
622
|
+
const debug = PaywalloClient.getConfig()?.debug;
|
|
623
|
+
if (debug) console.info(`[Paywallo PURCHASE] starting ${productId}`);
|
|
601
624
|
try {
|
|
602
625
|
const purchase = await nativeStoreKit.purchase(productId);
|
|
603
626
|
if (!purchase) {
|
|
627
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} cancelled`);
|
|
604
628
|
return { success: false };
|
|
605
629
|
}
|
|
606
|
-
|
|
607
|
-
let validation = null;
|
|
608
|
-
try {
|
|
609
|
-
validation = await this.validateWithServer(purchase, productId, options);
|
|
610
|
-
} catch (validationError) {
|
|
611
|
-
return {
|
|
612
|
-
success: false,
|
|
613
|
-
error: new PurchaseError(PURCHASE_ERROR_CODES.VALIDATION_FAILED, validationError instanceof Error ? validationError.message : "Server validation failed")
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
if (!validation?.success) {
|
|
617
|
-
return {
|
|
618
|
-
success: false,
|
|
619
|
-
error: new PurchaseError(PURCHASE_ERROR_CODES.VALIDATION_FAILED, validation?.error ? `Server validation: ${validation.error}` : "Server validation failed")
|
|
620
|
-
};
|
|
621
|
-
}
|
|
630
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} approved`, { transactionId: purchase.transactionId });
|
|
622
631
|
await this.finishTransaction(purchase.transactionId);
|
|
632
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} finished`);
|
|
633
|
+
this.validateWithServer(purchase, productId, options).then(() => {
|
|
634
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} server validated`);
|
|
635
|
+
}).catch((err) => {
|
|
636
|
+
if (debug) console.warn("[Paywallo PURCHASE] background validation failed", err);
|
|
637
|
+
});
|
|
623
638
|
return { success: true, purchase };
|
|
624
639
|
} catch (error) {
|
|
640
|
+
if (debug) console.warn(`[Paywallo PURCHASE] ${productId} failed`, error);
|
|
625
641
|
const e = error instanceof PurchaseError ? error : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, error instanceof Error ? error.message : String(error));
|
|
626
642
|
return { success: false, error: e };
|
|
627
643
|
}
|
|
@@ -657,13 +673,15 @@ var IAPService = class {
|
|
|
657
673
|
if (r.status === "fulfilled" && r.value.success) {
|
|
658
674
|
try {
|
|
659
675
|
await nativeStoreKit.finishTransaction(tx.transactionId);
|
|
660
|
-
} catch (
|
|
676
|
+
} catch (err) {
|
|
677
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] finishTransaction failed", err);
|
|
661
678
|
}
|
|
662
679
|
validated.push(tx);
|
|
663
680
|
}
|
|
664
681
|
}
|
|
665
682
|
return validated;
|
|
666
|
-
} catch (
|
|
683
|
+
} catch (err) {
|
|
684
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] restore failed", err);
|
|
667
685
|
return [];
|
|
668
686
|
}
|
|
669
687
|
}
|
|
@@ -693,7 +711,8 @@ function usePaywallTracking() {
|
|
|
693
711
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
694
712
|
...sessionId && { sessionId }
|
|
695
713
|
});
|
|
696
|
-
} catch {
|
|
714
|
+
} catch (err) {
|
|
715
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackDismissed failed", err);
|
|
697
716
|
}
|
|
698
717
|
}, []);
|
|
699
718
|
const trackProductSelected = useCallback((opts) => {
|
|
@@ -707,7 +726,8 @@ function usePaywallTracking() {
|
|
|
707
726
|
...opts.variantKey && { variantKey: opts.variantKey },
|
|
708
727
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
709
728
|
...sessionId && { sessionId }
|
|
710
|
-
}).catch(() => {
|
|
729
|
+
}).catch((err) => {
|
|
730
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackProductSelected failed", err);
|
|
711
731
|
});
|
|
712
732
|
}, []);
|
|
713
733
|
const trackPurchased = useCallback(async (opts) => {
|
|
@@ -723,7 +743,8 @@ function usePaywallTracking() {
|
|
|
723
743
|
...opts.campaignId && { campaignId: opts.campaignId },
|
|
724
744
|
...sessionId && { sessionId }
|
|
725
745
|
});
|
|
726
|
-
} catch {
|
|
746
|
+
} catch (err) {
|
|
747
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] trackPurchased failed", err);
|
|
727
748
|
}
|
|
728
749
|
}, []);
|
|
729
750
|
return { trackDismissed, trackProductSelected, trackPurchased };
|
|
@@ -863,7 +884,8 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
863
884
|
const map = /* @__PURE__ */ new Map();
|
|
864
885
|
for (const p of storeProducts) map.set(p.productId, p);
|
|
865
886
|
setProducts(map);
|
|
866
|
-
} catch {
|
|
887
|
+
} catch (err) {
|
|
888
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] loadProducts in paywall failed", err);
|
|
867
889
|
setProducts(/* @__PURE__ */ new Map());
|
|
868
890
|
}
|
|
869
891
|
} else {
|
|
@@ -1398,7 +1420,12 @@ var PaywallErrorBoundary = class extends Component {
|
|
|
1398
1420
|
static getDerivedStateFromError() {
|
|
1399
1421
|
return { hasError: true };
|
|
1400
1422
|
}
|
|
1401
|
-
componentDidCatch(
|
|
1423
|
+
componentDidCatch(error) {
|
|
1424
|
+
if (PaywalloClient.getConfig()?.debug) console.error("[Paywallo] Paywall render error:", error);
|
|
1425
|
+
try {
|
|
1426
|
+
PaywalloClient.getApiClient()?.reportError("PAYWALL_RENDER_ERROR", error.message);
|
|
1427
|
+
} catch {
|
|
1428
|
+
}
|
|
1402
1429
|
}
|
|
1403
1430
|
render() {
|
|
1404
1431
|
return this.state.hasError ? null : this.props.children;
|
|
@@ -1678,7 +1705,8 @@ var AffiliateManager = class {
|
|
|
1678
1705
|
);
|
|
1679
1706
|
}
|
|
1680
1707
|
}
|
|
1681
|
-
log(...
|
|
1708
|
+
log(...args) {
|
|
1709
|
+
if (this.debug) console.log("[Paywallo:Affiliate]", ...args);
|
|
1682
1710
|
}
|
|
1683
1711
|
};
|
|
1684
1712
|
var affiliateManager = new AffiliateManager();
|
|
@@ -1946,7 +1974,8 @@ var SubscriptionManagerClass = class {
|
|
|
1946
1974
|
await this.cache.invalidate(this.cacheKey());
|
|
1947
1975
|
await this.getSubscriptionStatus(true);
|
|
1948
1976
|
}
|
|
1949
|
-
log(...
|
|
1977
|
+
log(...args) {
|
|
1978
|
+
if (this.config?.debug) console.log("[Paywallo:Subscription]", ...args);
|
|
1950
1979
|
}
|
|
1951
1980
|
};
|
|
1952
1981
|
var subscriptionManager = new SubscriptionManagerClass();
|
|
@@ -1999,12 +2028,18 @@ async function validatePurchase(client, appKey, platform, receipt, productId, tr
|
|
|
1999
2028
|
},
|
|
2000
2029
|
false
|
|
2001
2030
|
);
|
|
2031
|
+
if (!response.ok) {
|
|
2032
|
+
throw new Error(`Server validation failed: HTTP ${response.status}`);
|
|
2033
|
+
}
|
|
2002
2034
|
return response.data;
|
|
2003
2035
|
}
|
|
2004
2036
|
async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
|
|
2005
2037
|
const url = new URL(`${baseUrl}/purchases/status/${appKey}`);
|
|
2006
2038
|
url.searchParams.set("distinctId", distinctId);
|
|
2007
2039
|
const response = await client.get(url.toString());
|
|
2040
|
+
if (!response.ok) {
|
|
2041
|
+
throw new Error(`Subscription status check failed: HTTP ${response.status}`);
|
|
2042
|
+
}
|
|
2008
2043
|
return response.data;
|
|
2009
2044
|
}
|
|
2010
2045
|
async function getEmergencyPaywall(client) {
|
|
@@ -2184,7 +2219,8 @@ var HttpClient = class {
|
|
|
2184
2219
|
sleep(ms) {
|
|
2185
2220
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2186
2221
|
}
|
|
2187
|
-
log(...
|
|
2222
|
+
log(...args) {
|
|
2223
|
+
if (this.config.debug) console.log("[Paywallo:Http]", ...args);
|
|
2188
2224
|
}
|
|
2189
2225
|
setDebug(debug) {
|
|
2190
2226
|
this.config.debug = debug;
|
|
@@ -2210,8 +2246,6 @@ var NetworkMonitorClass = class {
|
|
|
2210
2246
|
this.config = DEFAULT_NETWORK_CONFIG;
|
|
2211
2247
|
this.listeners = /* @__PURE__ */ new Set();
|
|
2212
2248
|
this.currentState = "unknown";
|
|
2213
|
-
this.netInfoModule = null;
|
|
2214
|
-
this.netInfoSubscription = null;
|
|
2215
2249
|
this.appStateSubscription = null;
|
|
2216
2250
|
this.initialized = false;
|
|
2217
2251
|
this.checkIntervalId = null;
|
|
@@ -2227,13 +2261,6 @@ var NetworkMonitorClass = class {
|
|
|
2227
2261
|
void this.setupFallbackDetection();
|
|
2228
2262
|
this.setupAppStateListener();
|
|
2229
2263
|
}
|
|
2230
|
-
setupNetInfoListener() {
|
|
2231
|
-
if (!this.netInfoModule) return;
|
|
2232
|
-
this.netInfoSubscription = this.netInfoModule.addEventListener((state) => {
|
|
2233
|
-
const newState = this.netInfoStateToNetworkState(state);
|
|
2234
|
-
this.updateState(newState);
|
|
2235
|
-
});
|
|
2236
|
-
}
|
|
2237
2264
|
async setupFallbackDetection() {
|
|
2238
2265
|
await this.checkConnectivity();
|
|
2239
2266
|
this.checkIntervalId = setInterval(() => {
|
|
@@ -2261,15 +2288,6 @@ var NetworkMonitorClass = class {
|
|
|
2261
2288
|
this.updateState("offline");
|
|
2262
2289
|
}
|
|
2263
2290
|
}
|
|
2264
|
-
netInfoStateToNetworkState(state) {
|
|
2265
|
-
if (state.isConnected === null) {
|
|
2266
|
-
return "unknown";
|
|
2267
|
-
}
|
|
2268
|
-
if (!state.isConnected) {
|
|
2269
|
-
return "offline";
|
|
2270
|
-
}
|
|
2271
|
-
return "online";
|
|
2272
|
-
}
|
|
2273
2291
|
updateState(newState) {
|
|
2274
2292
|
const previousState = this.currentState;
|
|
2275
2293
|
if (previousState === newState) {
|
|
@@ -2312,10 +2330,6 @@ var NetworkMonitorClass = class {
|
|
|
2312
2330
|
return this.currentState;
|
|
2313
2331
|
}
|
|
2314
2332
|
dispose() {
|
|
2315
|
-
if (this.netInfoSubscription) {
|
|
2316
|
-
this.netInfoSubscription();
|
|
2317
|
-
this.netInfoSubscription = null;
|
|
2318
|
-
}
|
|
2319
2333
|
if (this.appStateSubscription) {
|
|
2320
2334
|
this.appStateSubscription.remove();
|
|
2321
2335
|
this.appStateSubscription = null;
|
|
@@ -2328,7 +2342,8 @@ var NetworkMonitorClass = class {
|
|
|
2328
2342
|
this.initialized = false;
|
|
2329
2343
|
this.currentState = "unknown";
|
|
2330
2344
|
}
|
|
2331
|
-
log(...
|
|
2345
|
+
log(...args) {
|
|
2346
|
+
if (this.config.debug) console.log("[Paywallo:Network]", ...args);
|
|
2332
2347
|
}
|
|
2333
2348
|
setDebug(debug) {
|
|
2334
2349
|
this.config.debug = debug;
|
|
@@ -2338,6 +2353,7 @@ var networkMonitor = new NetworkMonitorClass();
|
|
|
2338
2353
|
|
|
2339
2354
|
// src/core/queue/OfflineQueue.ts
|
|
2340
2355
|
import AsyncStorage2 from "@react-native-async-storage/async-storage";
|
|
2356
|
+
init_uuid();
|
|
2341
2357
|
|
|
2342
2358
|
// src/core/queue/deduplication.ts
|
|
2343
2359
|
function normalizeForComparison(obj) {
|
|
@@ -2575,7 +2591,8 @@ var OfflineQueueClass = class {
|
|
|
2575
2591
|
}
|
|
2576
2592
|
}
|
|
2577
2593
|
}
|
|
2578
|
-
log(...
|
|
2594
|
+
log(...args) {
|
|
2595
|
+
if (this.config.debug) console.log("[Paywallo:Queue]", ...args);
|
|
2579
2596
|
}
|
|
2580
2597
|
setDebug(debug) {
|
|
2581
2598
|
this.config.debug = debug;
|
|
@@ -2717,7 +2734,8 @@ var QueueProcessorClass = class {
|
|
|
2717
2734
|
this.httpClient = null;
|
|
2718
2735
|
this.initialized = false;
|
|
2719
2736
|
}
|
|
2720
|
-
log(...
|
|
2737
|
+
log(...args) {
|
|
2738
|
+
if (this.config.debug) console.log("[Paywallo:QueueProcessor]", ...args);
|
|
2721
2739
|
}
|
|
2722
2740
|
setDebug(debug) {
|
|
2723
2741
|
this.config.debug = debug;
|
|
@@ -2799,13 +2817,12 @@ var ApiCache = class {
|
|
|
2799
2817
|
};
|
|
2800
2818
|
|
|
2801
2819
|
// src/core/ApiClient.ts
|
|
2802
|
-
var SDK_VERSION = "1.
|
|
2803
|
-
var DEFAULT_BASE_URL = "https://panel.lucasqueiroga.shop";
|
|
2820
|
+
var SDK_VERSION = "1.4.1";
|
|
2804
2821
|
var _ApiClient = class _ApiClient {
|
|
2805
|
-
constructor(appKey, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2822
|
+
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2806
2823
|
this.cache = new ApiCache();
|
|
2807
2824
|
this.appKey = appKey;
|
|
2808
|
-
this.baseUrl =
|
|
2825
|
+
this.baseUrl = apiUrl;
|
|
2809
2826
|
this.webUrl = deriveWebUrl(this.baseUrl);
|
|
2810
2827
|
this.debug = debug;
|
|
2811
2828
|
this.environment = environment;
|
|
@@ -2858,7 +2875,8 @@ var _ApiClient = class _ApiClient {
|
|
|
2858
2875
|
sdkVersion: SDK_VERSION,
|
|
2859
2876
|
platform: Platform5.OS
|
|
2860
2877
|
}, true);
|
|
2861
|
-
} catch {
|
|
2878
|
+
} catch (err) {
|
|
2879
|
+
if (this.debug) console.warn("[Paywallo:ApiClient] reportError failed", err);
|
|
2862
2880
|
}
|
|
2863
2881
|
}
|
|
2864
2882
|
async trackEvent(eventName, distinctId, properties, timestamp) {
|
|
@@ -2898,6 +2916,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2898
2916
|
try {
|
|
2899
2917
|
const res = await this.get(`/api/v1/flags/${flagKey}?distinctId=${encodeURIComponent(distinctId)}`);
|
|
2900
2918
|
if (res.status === 404) {
|
|
2919
|
+
this.log("Flag not found (404):", flagKey);
|
|
2901
2920
|
const v = { variant: null };
|
|
2902
2921
|
this.cache.setVariant(key, v, this.cache.nullTTL);
|
|
2903
2922
|
return v;
|
|
@@ -2924,6 +2943,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2924
2943
|
try {
|
|
2925
2944
|
const res = await this.get(`/api/v1/paywalls/${placement}`);
|
|
2926
2945
|
if (res.status === 404) {
|
|
2946
|
+
this.log("Paywall not found (404):", placement);
|
|
2927
2947
|
this.cache.setPaywall(placement, null, this.cache.nullTTL);
|
|
2928
2948
|
return null;
|
|
2929
2949
|
}
|
|
@@ -2975,6 +2995,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2975
2995
|
try {
|
|
2976
2996
|
const res = await this.get(`/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
2977
2997
|
if (res.status === 404) {
|
|
2998
|
+
this.log("Primary campaign not found (404)");
|
|
2978
2999
|
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
2979
3000
|
return null;
|
|
2980
3001
|
}
|
|
@@ -3025,7 +3046,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3025
3046
|
headers: { "X-App-Key": this.appKey, "x-distinct-id": distinctId }
|
|
3026
3047
|
});
|
|
3027
3048
|
if (!res.ok) {
|
|
3028
|
-
this.log("
|
|
3049
|
+
this.log("evaluateFlags failed:", res.status, keys);
|
|
3029
3050
|
return {};
|
|
3030
3051
|
}
|
|
3031
3052
|
const raw = res.data;
|
|
@@ -3090,7 +3111,8 @@ var _ApiClient = class _ApiClient {
|
|
|
3090
3111
|
try {
|
|
3091
3112
|
const value = JSON.stringify({ variant: flag.variant, payload: flag.payload, cachedAt: Date.now() });
|
|
3092
3113
|
await secureStorage.set(`flag:${flagKey}:${distinctId}`, value);
|
|
3093
|
-
} catch {
|
|
3114
|
+
} catch (err) {
|
|
3115
|
+
this.log("writeFlagToStorage failed", err);
|
|
3094
3116
|
}
|
|
3095
3117
|
}
|
|
3096
3118
|
async postWithQueue(url, payload, label) {
|
|
@@ -3111,7 +3133,8 @@ var _ApiClient = class _ApiClient {
|
|
|
3111
3133
|
throw error;
|
|
3112
3134
|
}
|
|
3113
3135
|
}
|
|
3114
|
-
log(...
|
|
3136
|
+
log(...args) {
|
|
3137
|
+
if (this.debug) console.log("[Paywallo:ApiClient]", ...args);
|
|
3115
3138
|
}
|
|
3116
3139
|
};
|
|
3117
3140
|
_ApiClient.FLAG_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
@@ -3279,36 +3302,60 @@ var AdvertisingIdManager = class {
|
|
|
3279
3302
|
}
|
|
3280
3303
|
};
|
|
3281
3304
|
|
|
3282
|
-
// src/domains/identity/
|
|
3305
|
+
// src/domains/identity/InstallTracker.ts
|
|
3306
|
+
import { Dimensions as Dimensions3, Platform as Platform8 } from "react-native";
|
|
3307
|
+
import AsyncStorage3 from "@react-native-async-storage/async-storage";
|
|
3308
|
+
import RNDeviceInfo from "react-native-device-info";
|
|
3309
|
+
|
|
3310
|
+
// src/domains/identity/MetaBridge.ts
|
|
3311
|
+
import { NativeModules as NativeModules4 } from "react-native";
|
|
3283
3312
|
var TIMEOUT_MS = 2e3;
|
|
3284
|
-
var
|
|
3285
|
-
|
|
3313
|
+
var NativeBridge = NativeModules4.PaywalloFBBridge ?? null;
|
|
3314
|
+
var MetaBridge = class {
|
|
3315
|
+
async getAnonymousID() {
|
|
3316
|
+
if (!NativeBridge) return null;
|
|
3286
3317
|
try {
|
|
3287
3318
|
let timerId;
|
|
3288
|
-
const
|
|
3319
|
+
const timeout = new Promise((resolve) => {
|
|
3289
3320
|
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
3290
3321
|
});
|
|
3291
|
-
const result = await Promise.race([
|
|
3322
|
+
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
3292
3323
|
clearTimeout(timerId);
|
|
3293
3324
|
return result;
|
|
3294
3325
|
} catch {
|
|
3295
3326
|
return null;
|
|
3296
3327
|
}
|
|
3297
3328
|
}
|
|
3298
|
-
async
|
|
3329
|
+
async logEvent(name, params = {}) {
|
|
3330
|
+
if (!NativeBridge) return;
|
|
3299
3331
|
try {
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3332
|
+
await NativeBridge.logEvent(name, params);
|
|
3333
|
+
} catch {
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
async logPurchase(amount, currency, params = {}) {
|
|
3337
|
+
if (!NativeBridge) return;
|
|
3338
|
+
try {
|
|
3339
|
+
await NativeBridge.logPurchase(amount, currency, params);
|
|
3340
|
+
} catch {
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
setUserID(userId) {
|
|
3344
|
+
if (!NativeBridge) return;
|
|
3345
|
+
try {
|
|
3346
|
+
NativeBridge.setUserID(userId);
|
|
3347
|
+
} catch {
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
flush() {
|
|
3351
|
+
if (!NativeBridge) return;
|
|
3352
|
+
try {
|
|
3353
|
+
NativeBridge.flush();
|
|
3303
3354
|
} catch {
|
|
3304
|
-
return null;
|
|
3305
3355
|
}
|
|
3306
3356
|
}
|
|
3307
3357
|
};
|
|
3308
|
-
var
|
|
3309
|
-
|
|
3310
|
-
// src/domains/identity/InstallTracker.ts
|
|
3311
|
-
import { Dimensions as Dimensions3, Platform as Platform8 } from "react-native";
|
|
3358
|
+
var metaBridge = new MetaBridge();
|
|
3312
3359
|
|
|
3313
3360
|
// src/domains/identity/InstallReferrerManager.ts
|
|
3314
3361
|
import { Platform as Platform7 } from "react-native";
|
|
@@ -3376,6 +3423,7 @@ var installReferrerManager = new InstallReferrerManager();
|
|
|
3376
3423
|
|
|
3377
3424
|
// src/domains/session/SessionManager.ts
|
|
3378
3425
|
import { AppState as AppState2 } from "react-native";
|
|
3426
|
+
init_uuid();
|
|
3379
3427
|
|
|
3380
3428
|
// src/domains/session/sessionTracking.ts
|
|
3381
3429
|
async function trackSessionStart(apiClient, sessionId, sessionStartedAt) {
|
|
@@ -3604,7 +3652,8 @@ var SessionManager = class {
|
|
|
3604
3652
|
);
|
|
3605
3653
|
}
|
|
3606
3654
|
}
|
|
3607
|
-
log(...
|
|
3655
|
+
log(...args) {
|
|
3656
|
+
if (this.debug) console.log("[Paywallo:Session]", ...args);
|
|
3608
3657
|
}
|
|
3609
3658
|
};
|
|
3610
3659
|
var sessionManager = new SessionManager();
|
|
@@ -3617,11 +3666,10 @@ var InstallTracker = class {
|
|
|
3617
3666
|
}
|
|
3618
3667
|
async trackIfNeeded(apiClient, requestATT = false) {
|
|
3619
3668
|
const storage = new SecureStorage(this.debug);
|
|
3620
|
-
const alreadyTracked = await storage.get("install_tracked");
|
|
3669
|
+
const alreadyTracked = await storage.get("@panel:install_tracked");
|
|
3621
3670
|
if (alreadyTracked) return;
|
|
3622
3671
|
let fallbackTracked = null;
|
|
3623
3672
|
try {
|
|
3624
|
-
const AsyncStorage3 = (await import("@react-native-async-storage/async-storage")).default;
|
|
3625
3673
|
fallbackTracked = await AsyncStorage3.getItem("@paywallo:install_tracked");
|
|
3626
3674
|
} catch {
|
|
3627
3675
|
}
|
|
@@ -3630,13 +3678,7 @@ var InstallTracker = class {
|
|
|
3630
3678
|
const sessionId = sessionManager.getSessionId();
|
|
3631
3679
|
const installedAt = Date.now();
|
|
3632
3680
|
if (!distinctId) return;
|
|
3633
|
-
|
|
3634
|
-
try {
|
|
3635
|
-
const mod = await import("react-native-device-info");
|
|
3636
|
-
deviceInfo = mod.default;
|
|
3637
|
-
} catch {
|
|
3638
|
-
deviceInfo = null;
|
|
3639
|
-
}
|
|
3681
|
+
const deviceInfo = RNDeviceInfo;
|
|
3640
3682
|
let deviceData = {};
|
|
3641
3683
|
try {
|
|
3642
3684
|
const screen = Dimensions3.get("screen");
|
|
@@ -3648,6 +3690,38 @@ var InstallTracker = class {
|
|
|
3648
3690
|
const osVersion = deviceInfo?.getSystemVersion() || "unknown";
|
|
3649
3691
|
const appVersion = deviceInfo?.getVersion() || "unknown";
|
|
3650
3692
|
const buildNumber = deviceInfo?.getBuildNumber() || "0";
|
|
3693
|
+
let carrier = "unknown";
|
|
3694
|
+
try {
|
|
3695
|
+
carrier = await deviceInfo?.getCarrier?.() ?? "unknown";
|
|
3696
|
+
} catch {
|
|
3697
|
+
}
|
|
3698
|
+
let totalDisk = 0;
|
|
3699
|
+
try {
|
|
3700
|
+
totalDisk = Number(await deviceInfo?.getTotalDiskCapacity?.()) || 0;
|
|
3701
|
+
} catch {
|
|
3702
|
+
}
|
|
3703
|
+
let freeDisk = 0;
|
|
3704
|
+
try {
|
|
3705
|
+
freeDisk = Number(await deviceInfo?.getFreeDiskStorage?.()) || 0;
|
|
3706
|
+
} catch {
|
|
3707
|
+
}
|
|
3708
|
+
let totalRam = 0;
|
|
3709
|
+
try {
|
|
3710
|
+
totalRam = Number(await deviceInfo?.getTotalMemory?.()) || 0;
|
|
3711
|
+
} catch {
|
|
3712
|
+
}
|
|
3713
|
+
let brand = "unknown";
|
|
3714
|
+
try {
|
|
3715
|
+
brand = deviceInfo?.getBrand?.() ?? "unknown";
|
|
3716
|
+
} catch {
|
|
3717
|
+
}
|
|
3718
|
+
let installerPackage = null;
|
|
3719
|
+
try {
|
|
3720
|
+
if (Platform8.OS === "android") {
|
|
3721
|
+
installerPackage = await deviceInfo?.getInstallerPackageName?.() ?? null;
|
|
3722
|
+
}
|
|
3723
|
+
} catch {
|
|
3724
|
+
}
|
|
3651
3725
|
deviceData = {
|
|
3652
3726
|
deviceModel,
|
|
3653
3727
|
osVersion,
|
|
@@ -3656,22 +3730,40 @@ var InstallTracker = class {
|
|
|
3656
3730
|
...screenWidth > 0 && { screenWidth },
|
|
3657
3731
|
...screenHeight > 0 && { screenHeight },
|
|
3658
3732
|
timezone,
|
|
3659
|
-
locale
|
|
3733
|
+
locale,
|
|
3734
|
+
...carrier !== "unknown" && { carrier },
|
|
3735
|
+
...totalDisk > 0 && { totalDisk },
|
|
3736
|
+
...freeDisk > 0 && { freeDisk },
|
|
3737
|
+
...totalRam > 0 && { totalRam },
|
|
3738
|
+
...brand !== "unknown" && { brand },
|
|
3739
|
+
...installerPackage && { installerPackage }
|
|
3660
3740
|
};
|
|
3661
3741
|
} catch {
|
|
3662
3742
|
}
|
|
3663
3743
|
const [fbAnonId, referrer, adIds] = await Promise.all([
|
|
3664
|
-
|
|
3744
|
+
metaBridge.getAnonymousID(),
|
|
3665
3745
|
installReferrerManager.getReferrer(),
|
|
3666
3746
|
this.advertisingIdManager.collect(requestATT)
|
|
3667
3747
|
]);
|
|
3748
|
+
let effectiveAnonId = fbAnonId;
|
|
3749
|
+
if (!effectiveAnonId) {
|
|
3750
|
+
const stored = await storage.get("@panel:anon_id");
|
|
3751
|
+
if (stored) {
|
|
3752
|
+
effectiveAnonId = stored;
|
|
3753
|
+
} else {
|
|
3754
|
+
const { generateUUID: generateUUID2 } = await Promise.resolve().then(() => (init_uuid(), uuid_exports));
|
|
3755
|
+
effectiveAnonId = `PW_${generateUUID2()}`;
|
|
3756
|
+
await storage.set("@panel:anon_id", effectiveAnonId).catch(() => {
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3668
3760
|
try {
|
|
3669
3761
|
await apiClient.trackEvent("$app_installed", distinctId, {
|
|
3670
3762
|
installedAt,
|
|
3671
3763
|
platform: Platform8.OS,
|
|
3672
3764
|
...sessionId && { sessionId },
|
|
3673
3765
|
...deviceData,
|
|
3674
|
-
...
|
|
3766
|
+
...effectiveAnonId && { fbAnonId: effectiveAnonId },
|
|
3675
3767
|
...referrer.rawReferrer && { installReferrer: referrer.rawReferrer },
|
|
3676
3768
|
...referrer.trackingId && { referrerTrackingId: referrer.trackingId },
|
|
3677
3769
|
...referrer.fbclid && { referrerFbclid: referrer.fbclid },
|
|
@@ -3683,15 +3775,49 @@ var InstallTracker = class {
|
|
|
3683
3775
|
...adIds.gaid && { gaid: adIds.gaid },
|
|
3684
3776
|
attStatus: adIds.attStatus
|
|
3685
3777
|
});
|
|
3686
|
-
|
|
3778
|
+
if (Platform8.OS === "ios") {
|
|
3779
|
+
void this.callDeferredMatch(apiClient, deviceData, adIds, effectiveAnonId).catch(() => {
|
|
3780
|
+
});
|
|
3781
|
+
}
|
|
3782
|
+
await storage.set("@panel:install_tracked", String(installedAt));
|
|
3687
3783
|
try {
|
|
3688
|
-
const AsyncStorage3 = (await import("@react-native-async-storage/async-storage")).default;
|
|
3689
3784
|
await AsyncStorage3.setItem("@paywallo:install_tracked", String(installedAt));
|
|
3690
3785
|
} catch {
|
|
3691
3786
|
}
|
|
3692
3787
|
} catch {
|
|
3693
3788
|
}
|
|
3694
3789
|
}
|
|
3790
|
+
async callDeferredMatch(apiClient, deviceData, adIds, anonId) {
|
|
3791
|
+
const storage = new SecureStorage(this.debug);
|
|
3792
|
+
const alreadyMatched = await storage.get("@panel:deferred_match_done");
|
|
3793
|
+
if (alreadyMatched) return;
|
|
3794
|
+
const controller = new AbortController();
|
|
3795
|
+
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
3796
|
+
try {
|
|
3797
|
+
const baseUrl = apiClient.getBaseUrl();
|
|
3798
|
+
const appKey = apiClient.appKey;
|
|
3799
|
+
await fetch(`${baseUrl}/api/v1/attribution/deferred-match`, {
|
|
3800
|
+
method: "POST",
|
|
3801
|
+
headers: { "Content-Type": "application/json", "X-App-Key": appKey },
|
|
3802
|
+
body: JSON.stringify({
|
|
3803
|
+
idfv: adIds.idfv,
|
|
3804
|
+
deviceModel: deviceData.deviceModel,
|
|
3805
|
+
osVersion: deviceData.osVersion,
|
|
3806
|
+
screenWidth: deviceData.screenWidth,
|
|
3807
|
+
screenHeight: deviceData.screenHeight,
|
|
3808
|
+
timezone: deviceData.timezone,
|
|
3809
|
+
locale: deviceData.locale,
|
|
3810
|
+
fbAnonId: anonId
|
|
3811
|
+
}),
|
|
3812
|
+
signal: controller.signal
|
|
3813
|
+
});
|
|
3814
|
+
await storage.set("@panel:deferred_match_done", "1").catch(() => {
|
|
3815
|
+
});
|
|
3816
|
+
} catch {
|
|
3817
|
+
} finally {
|
|
3818
|
+
clearTimeout(timer);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3695
3821
|
};
|
|
3696
3822
|
|
|
3697
3823
|
// src/core/PaywalloClient.ts
|
|
@@ -3783,9 +3909,12 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3783
3909
|
this.networkCleanup = networkMonitor.addListener((state) => {
|
|
3784
3910
|
if (state !== "online") return;
|
|
3785
3911
|
if (this.config && this.apiClient) return;
|
|
3912
|
+
if (this.initPromise) return;
|
|
3786
3913
|
this.initPromise = this.initWithRetry(config);
|
|
3787
3914
|
this.initPromise.catch(() => {
|
|
3788
3915
|
this.reportInitFailure(config, null, "NETWORK_RECOVERY_FAILED");
|
|
3916
|
+
}).finally(() => {
|
|
3917
|
+
if (!this.isReady()) this.initPromise = null;
|
|
3789
3918
|
});
|
|
3790
3919
|
});
|
|
3791
3920
|
}
|
|
@@ -3797,12 +3926,13 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3797
3926
|
}
|
|
3798
3927
|
reportInitFailure(config, error, reason) {
|
|
3799
3928
|
try {
|
|
3800
|
-
const tempClient = new ApiClient(config.appKey, config.debug);
|
|
3929
|
+
const tempClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug);
|
|
3801
3930
|
void tempClient.reportError("INIT_FAILED", reason, {
|
|
3802
3931
|
attempts: this.initAttempts,
|
|
3803
3932
|
error: error instanceof Error ? error.message : String(error)
|
|
3804
3933
|
});
|
|
3805
|
-
} catch {
|
|
3934
|
+
} catch (err) {
|
|
3935
|
+
if (config.debug) console.warn("[Paywallo] reportInitFailure error", err);
|
|
3806
3936
|
}
|
|
3807
3937
|
}
|
|
3808
3938
|
reportInitSuccess(config, attempts) {
|
|
@@ -3810,7 +3940,8 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3810
3940
|
if (this.apiClient) {
|
|
3811
3941
|
void this.apiClient.reportError("INIT_RECOVERED", `Succeeded after ${attempts} retries`, { attempts });
|
|
3812
3942
|
}
|
|
3813
|
-
} catch {
|
|
3943
|
+
} catch (err) {
|
|
3944
|
+
if (config.debug) console.warn("[Paywallo] reportInitSuccess error", err);
|
|
3814
3945
|
}
|
|
3815
3946
|
}
|
|
3816
3947
|
async resolveSessionFlags(keys, apiClient, distinctId) {
|
|
@@ -3835,7 +3966,7 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3835
3966
|
() => offlineQueue.clearItemsWithInvalidAppKey(config.appKey)
|
|
3836
3967
|
)
|
|
3837
3968
|
]);
|
|
3838
|
-
this.apiClient = new ApiClient(config.appKey, config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
3969
|
+
this.apiClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
3839
3970
|
queueProcessor.initialize(this.apiClient.getHttpClient(), { debug: config.debug });
|
|
3840
3971
|
affiliateManager.initialize(this.apiClient, config.debug);
|
|
3841
3972
|
subscriptionManager.init({
|
|
@@ -3889,18 +4020,21 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3889
4020
|
}
|
|
3890
4021
|
async identify(options) {
|
|
3891
4022
|
this.ensureInitialized();
|
|
4023
|
+
if (this.config?.debug) console.info("[Paywallo IDENTIFY]", options);
|
|
3892
4024
|
await identityManager.identify(options);
|
|
3893
4025
|
}
|
|
3894
4026
|
async track(eventName, options) {
|
|
3895
4027
|
const apiClient = this.getApiClientOrThrow();
|
|
3896
4028
|
const distinctId = identityManager.getDistinctId();
|
|
3897
4029
|
if (!distinctId) {
|
|
4030
|
+
if (this.config?.debug) console.info(`[Paywallo TRACK] ${eventName} skipped (no distinctId)`);
|
|
3898
4031
|
return;
|
|
3899
4032
|
}
|
|
3900
4033
|
if (!isValidEventName(eventName)) {
|
|
3901
4034
|
const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
|
|
3902
4035
|
throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
|
|
3903
4036
|
}
|
|
4037
|
+
if (this.config?.debug && eventName.startsWith("$purchase")) console.info(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
3904
4038
|
const sessionId = sessionManager.getSessionId();
|
|
3905
4039
|
await apiClient.trackEvent(eventName, distinctId, {
|
|
3906
4040
|
...identityManager.getProperties(),
|
|
@@ -3921,14 +4055,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3921
4055
|
const now = Date.now();
|
|
3922
4056
|
const timeOnPreviousStep = this.lastOnboardingStepTimestamp !== null ? Math.round((now - this.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
3923
4057
|
this.lastOnboardingStepTimestamp = now;
|
|
3924
|
-
const sessionId = sessionManager.getSessionId();
|
|
3925
4058
|
await apiClient.trackEvent("$onboarding_step", distinctId, {
|
|
3926
|
-
...identityManager.getProperties(),
|
|
3927
4059
|
stepIndex: index,
|
|
3928
4060
|
stepName: name,
|
|
3929
|
-
|
|
3930
|
-
timeOnPreviousStep,
|
|
3931
|
-
...sessionId && { sessionId }
|
|
4061
|
+
timeOnPreviousStep
|
|
3932
4062
|
});
|
|
3933
4063
|
}
|
|
3934
4064
|
async coreAction(actionName) {
|
|
@@ -3963,10 +4093,14 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3963
4093
|
try {
|
|
3964
4094
|
const distinctId = identityManager.getDistinctId();
|
|
3965
4095
|
if (!distinctId) {
|
|
4096
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192 null (no distinctId)`);
|
|
3966
4097
|
return { variant: null };
|
|
3967
4098
|
}
|
|
3968
|
-
|
|
4099
|
+
const result = await this.getApiClientOrThrow().getVariant(flagKey, distinctId);
|
|
4100
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192`, result.variant);
|
|
4101
|
+
return result;
|
|
3969
4102
|
} catch (error) {
|
|
4103
|
+
if (this.config?.debug) console.warn(`[Paywallo FLAG] ${flagKey} \u2192 error`, error);
|
|
3970
4104
|
if (this.apiClient) void this.apiClient.reportError("GET_VARIANT_FAILED", error instanceof Error ? error.message : String(error));
|
|
3971
4105
|
return { variant: null };
|
|
3972
4106
|
}
|
|
@@ -3999,21 +4133,34 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
3999
4133
|
}
|
|
4000
4134
|
async presentCampaign(placement, context) {
|
|
4001
4135
|
this.ensureInitialized();
|
|
4002
|
-
|
|
4136
|
+
if (this.config?.debug) console.info(`[Paywallo CAMPAIGN] presenting ${placement}`);
|
|
4137
|
+
const result = await campaignGateService.presentCampaign(this.getApiClientOrThrow(), placement, () => this.hasActiveSubscription(), this.paywallPresenter, this.campaignPresenter, context);
|
|
4138
|
+
if (this.config?.debug) {
|
|
4139
|
+
if (result.error) console.warn(`[Paywallo CAMPAIGN] ${placement} error:`, result.error.message);
|
|
4140
|
+
else console.info(`[Paywallo CAMPAIGN] ${placement} result:`, { purchased: result.purchased, cancelled: result.cancelled, restored: result.restored, skippedReason: result.skippedReason });
|
|
4141
|
+
}
|
|
4142
|
+
return result;
|
|
4003
4143
|
}
|
|
4004
4144
|
async hasActiveSubscription() {
|
|
4005
4145
|
this.ensureInitialized();
|
|
4006
4146
|
try {
|
|
4007
4147
|
if (this.activeChecker) {
|
|
4008
|
-
|
|
4148
|
+
const result = await this.activeChecker();
|
|
4149
|
+
const isActive2 = result === true;
|
|
4150
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (checker):", isActive2);
|
|
4151
|
+
return isActive2;
|
|
4009
4152
|
}
|
|
4010
4153
|
const distinctId = identityManager.getDistinctId();
|
|
4011
4154
|
if (!distinctId || !this.apiClient) {
|
|
4155
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription: false (no distinctId/apiClient)");
|
|
4012
4156
|
return false;
|
|
4013
4157
|
}
|
|
4014
4158
|
const status = await this.apiClient.getSubscriptionStatus(distinctId);
|
|
4015
|
-
|
|
4159
|
+
const isActive = status.hasActiveSubscription === true;
|
|
4160
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (server):", isActive);
|
|
4161
|
+
return isActive;
|
|
4016
4162
|
} catch (error) {
|
|
4163
|
+
if (this.config?.debug) console.warn("[Paywallo SUB] hasActiveSubscription error", error);
|
|
4017
4164
|
if (this.apiClient) void this.apiClient.reportError("SUBSCRIPTION_CHECK_FAILED", error instanceof Error ? error.message : "hasActiveSubscription failed");
|
|
4018
4165
|
return false;
|
|
4019
4166
|
}
|
|
@@ -4034,7 +4181,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4034
4181
|
async restorePurchases() {
|
|
4035
4182
|
this.ensureInitialized();
|
|
4036
4183
|
if (!this.restoreHandler) throw new PaywallError(PAYWALL_ERROR_CODES.NOT_INITIALIZED, "PaywalloProvider not mounted. Wrap your app with <PaywalloProvider>");
|
|
4037
|
-
|
|
4184
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] starting");
|
|
4185
|
+
const result = await this.restoreHandler();
|
|
4186
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] result:", { success: result.success, restoredProducts: result.restoredProducts?.length ?? 0 });
|
|
4187
|
+
return result;
|
|
4038
4188
|
}
|
|
4039
4189
|
async reset() {
|
|
4040
4190
|
await identityManager.reset();
|
|
@@ -4320,9 +4470,7 @@ function usePurchase() {
|
|
|
4320
4470
|
setError(null);
|
|
4321
4471
|
try {
|
|
4322
4472
|
const iapService = getIAPService();
|
|
4323
|
-
const result = await iapService.purchase(productId
|
|
4324
|
-
onValidating: () => setState("validating")
|
|
4325
|
-
});
|
|
4473
|
+
const result = await iapService.purchase(productId);
|
|
4326
4474
|
if (result.success && result.purchase) {
|
|
4327
4475
|
setState("idle");
|
|
4328
4476
|
return {
|
|
@@ -4378,9 +4526,7 @@ function usePurchase() {
|
|
|
4378
4526
|
purchase,
|
|
4379
4527
|
restore,
|
|
4380
4528
|
error,
|
|
4381
|
-
|
|
4382
|
-
isPurchasing: state === "purchasing" || state === "validating",
|
|
4383
|
-
isValidating: state === "validating",
|
|
4529
|
+
isPurchasing: state === "purchasing",
|
|
4384
4530
|
isRestoring: state === "restoring"
|
|
4385
4531
|
};
|
|
4386
4532
|
}
|
|
@@ -4421,6 +4567,9 @@ function useSubscription() {
|
|
|
4421
4567
|
void subscriptionManager.getSubscriptionStatus().then((s) => {
|
|
4422
4568
|
setStatus(s);
|
|
4423
4569
|
setIsLoading(false);
|
|
4570
|
+
}).catch((err) => {
|
|
4571
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
4572
|
+
setIsLoading(false);
|
|
4424
4573
|
});
|
|
4425
4574
|
const removeListener = subscriptionManager.addListener((newStatus) => {
|
|
4426
4575
|
setStatus(newStatus);
|
|
@@ -4600,7 +4749,8 @@ function useProductLoader() {
|
|
|
4600
4749
|
const map = /* @__PURE__ */ new Map();
|
|
4601
4750
|
for (const p of loaded) map.set(p.productId, p);
|
|
4602
4751
|
setProducts(map);
|
|
4603
|
-
} catch (
|
|
4752
|
+
} catch (err) {
|
|
4753
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] refreshProducts failed", err);
|
|
4604
4754
|
} finally {
|
|
4605
4755
|
setIsLoadingProducts(false);
|
|
4606
4756
|
}
|
|
@@ -4640,6 +4790,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4640
4790
|
clearPreloadedWebView();
|
|
4641
4791
|
resolvePreloadedPaywall({ presented: true, purchased: true, cancelled: false, restored: false });
|
|
4642
4792
|
} catch (error) {
|
|
4793
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] preloaded purchase failed", error);
|
|
4643
4794
|
setShowingPreloadedWebView(false);
|
|
4644
4795
|
clearPreloadedWebView();
|
|
4645
4796
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -4660,6 +4811,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4660
4811
|
clearPreloadedWebView();
|
|
4661
4812
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: true });
|
|
4662
4813
|
} catch (error) {
|
|
4814
|
+
if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] preloaded restore failed", error);
|
|
4663
4815
|
setShowingPreloadedWebView(false);
|
|
4664
4816
|
clearPreloadedWebView();
|
|
4665
4817
|
resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
|
|
@@ -4772,7 +4924,7 @@ function useSubscriptionSync() {
|
|
|
4772
4924
|
cacheRef.current = { data: sub, expiresAt: Date.now() + CACHE_TTL_MS2 };
|
|
4773
4925
|
setSubscription(sub);
|
|
4774
4926
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
4775
|
-
return status.hasActiveSubscription;
|
|
4927
|
+
return status.hasActiveSubscription === true;
|
|
4776
4928
|
} catch {
|
|
4777
4929
|
return await resolveOfflineFromCache(distinctId);
|
|
4778
4930
|
}
|
|
@@ -5236,6 +5388,7 @@ export {
|
|
|
5236
5388
|
IDENTITY_ERROR_CODES,
|
|
5237
5389
|
IdentityError,
|
|
5238
5390
|
IdentityManager,
|
|
5391
|
+
MetaBridge,
|
|
5239
5392
|
PAYWALL_ERROR_CODES,
|
|
5240
5393
|
PURCHASE_ERROR_CODES,
|
|
5241
5394
|
PaywallContext,
|
|
@@ -5263,6 +5416,7 @@ export {
|
|
|
5263
5416
|
hasVariables,
|
|
5264
5417
|
identityManager,
|
|
5265
5418
|
initLocalization,
|
|
5419
|
+
metaBridge,
|
|
5266
5420
|
nativeStoreKit,
|
|
5267
5421
|
networkMonitor,
|
|
5268
5422
|
offlineQueue,
|