@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/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/utils/uuid.ts
121
- function generateUUID() {
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
- var _keychain = void 0;
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 _keychain !== null && _keychain !== void 0;
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 keychain.getGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
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 keychain.setGenericPassword("panel", value, { service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
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 keychain.resetGenericPassword({ service: `${KEYCHAIN_SERVICE_PREFIX}${key}` });
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
- if (DeviceInfo) {
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 result = await PaywalloStoreKitNative.purchase(productId, distinctId ?? null);
491
- if (!result || result.pending) {
492
- return null;
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
- await PaywalloStoreKitNative.finishTransaction(transactionId);
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
- const results = await PaywalloStoreKitNative.getActiveTransactions();
503
- return results.map(mapNativePurchase);
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 (error) {
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 (finishError) {
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
- options?.onValidating?.();
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 (finishError) {
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 (error) {
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(_error) {
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(..._args) {
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(..._args) {
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(..._args) {
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(..._args) {
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(..._args) {
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(..._args) {
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.0.0";
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 = DEFAULT_BASE_URL;
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("Non-OK response for evaluateFlags:", res.status);
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(..._args) {
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/FacebookIdManager.ts
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 FacebookIdManager = class {
3285
- async getAnonId() {
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 timeoutPromise = new Promise((resolve) => {
3319
+ const timeout = new Promise((resolve) => {
3289
3320
  timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
3290
3321
  });
3291
- const result = await Promise.race([this.fetchAnonId(), timeoutPromise]);
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 fetchAnonId() {
3329
+ async logEvent(name, params = {}) {
3330
+ if (!NativeBridge) return;
3299
3331
  try {
3300
- const fbsdk = await import("react-native-fbsdk-next");
3301
- const anonId = await fbsdk.AppEventsLogger.getAnonymousID();
3302
- return anonId || null;
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 facebookIdManager = new FacebookIdManager();
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(..._args) {
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
- let deviceInfo = null;
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
- facebookIdManager.getAnonId(),
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
- ...fbAnonId && { fbAnonId },
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
- const stored = await storage.set("install_tracked", String(installedAt));
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
- timestamp: now,
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
- return await this.getApiClientOrThrow().getVariant(flagKey, distinctId);
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
- return campaignGateService.presentCampaign(this.getApiClientOrThrow(), placement, () => this.hasActiveSubscription(), this.paywallPresenter, this.campaignPresenter, context);
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
- return await this.activeChecker();
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
- return status.hasActiveSubscription;
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
- return this.restoreHandler();
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
- isLoading: state === "loading",
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 (error) {
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,