@virex-tech/paywallo-sdk 1.0.0 → 1.1.0

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
@@ -133,8 +133,8 @@ async function loadKeychain() {
133
133
  }
134
134
  var KEYCHAIN_SERVICE_PREFIX = "com.paywallo.sdk.";
135
135
  var SecureStorage = class {
136
- constructor(debug = false) {
137
- this.debug = debug;
136
+ // eslint-disable-next-line @typescript-eslint/no-useless-constructor
137
+ constructor(_debug = false) {
138
138
  }
139
139
  /**
140
140
  * Get a value, trying Keychain first (survives reinstalls on iOS), then AsyncStorage.
@@ -142,18 +142,15 @@ var SecureStorage = class {
142
142
  async get(key) {
143
143
  const keychainValue = await this.getFromKeychain(key);
144
144
  if (keychainValue) {
145
- this.log(`Retrieved ${key} from keychain`);
146
145
  return keychainValue;
147
146
  }
148
147
  try {
149
148
  const value = await AsyncStorage.getItem(`@paywallo:${key}`);
150
149
  if (value) {
151
- this.log(`Retrieved ${key} from async storage`);
152
150
  await this.setToKeychain(key, value);
153
151
  }
154
152
  return value;
155
- } catch (error) {
156
- this.log(`Storage read failed for ${key}:`, error);
153
+ } catch {
157
154
  return null;
158
155
  }
159
156
  }
@@ -166,10 +163,8 @@ var SecureStorage = class {
166
163
  AsyncStorage.setItem(`@paywallo:${key}`, value),
167
164
  this.setToKeychain(key, value)
168
165
  ]);
169
- this.log(`Stored ${key} in storage`);
170
166
  return true;
171
- } catch (error) {
172
- this.log(`Storage write failed for ${key}:`, error);
167
+ } catch {
173
168
  return false;
174
169
  }
175
170
  }
@@ -179,10 +174,8 @@ var SecureStorage = class {
179
174
  AsyncStorage.removeItem(`@paywallo:${key}`),
180
175
  this.removeFromKeychain(key)
181
176
  ]);
182
- this.log(`Removed ${key} from storage`);
183
177
  return true;
184
- } catch (error) {
185
- this.log(`Storage remove failed for ${key}:`, error);
178
+ } catch {
186
179
  return false;
187
180
  }
188
181
  }
@@ -222,11 +215,6 @@ var SecureStorage = class {
222
215
  return false;
223
216
  }
224
217
  }
225
- log(...args) {
226
- if (this.debug) {
227
- console.warn("[Panel Storage]", ...args);
228
- }
229
- }
230
218
  };
231
219
  var secureStorage = new SecureStorage();
232
220
 
@@ -551,21 +539,13 @@ var IAPService = class {
551
539
  }
552
540
  async loadProducts(productIds) {
553
541
  if (!nativeStoreKit.isAvailable()) {
554
- if (this.debug) console.warn("[Paywallo][Products] StoreKit not available");
555
542
  return [];
556
543
  }
557
544
  try {
558
- if (this.debug) console.warn("[Paywallo][Products] Loading from StoreKit:", productIds);
559
545
  const products = await nativeStoreKit.getProducts(productIds);
560
- if (this.debug) console.warn("[Paywallo][Products] StoreKit returned:", products.length, "products");
561
546
  for (const product of products) {
562
- if (this.debug) console.warn("[Paywallo][Products]", product.productId, "\u2192", product.localizedPrice, "(", product.currency, ")");
563
547
  this.productsCache.set(product.productId, product);
564
548
  }
565
- if (products.length < productIds.length) {
566
- const missing = productIds.filter((id) => !products.find((p) => p.productId === id));
567
- if (this.debug) console.warn("[Paywallo][Products] Missing from StoreKit:", missing);
568
- }
569
549
  return products;
570
550
  } catch (error) {
571
551
  if (this.debug) console.warn("[Paywallo][Products] StoreKit error:", error);
@@ -583,7 +563,6 @@ var IAPService = class {
583
563
  const product = this.productsCache.get(productId);
584
564
  const platform = Platform2.OS;
585
565
  const distinctId = PaywalloClient.getDistinctId();
586
- if (this.debug) console.warn("[Paywallo][Purchase] Validating with server:", purchase.productId, "tx:", purchase.transactionId, "price:", product?.priceValue, product?.currency);
587
566
  const validation = await apiClient.validatePurchase(
588
567
  platform,
589
568
  purchase.receipt,
@@ -596,33 +575,28 @@ var IAPService = class {
596
575
  options?.paywallPlacement,
597
576
  options?.variantKey
598
577
  );
599
- if (this.debug) console.warn("[Paywallo][Purchase] Server validation result:", JSON.stringify(validation));
600
578
  return validation;
601
579
  }
602
580
  async finishTransaction(transactionId) {
603
581
  try {
604
- if (this.debug) console.warn("[Paywallo][Purchase] Finishing transaction:", transactionId);
605
582
  await nativeStoreKit.finishTransaction(transactionId);
606
- if (this.debug) console.warn("[Paywallo][Purchase] Transaction finished OK");
607
583
  } catch (finishError) {
608
584
  if (this.debug) console.warn("[Paywallo][Purchase] Failed to finish transaction:", finishError instanceof Error ? finishError.message : finishError);
609
585
  }
610
586
  }
611
587
  async purchase(productId, options) {
612
588
  if (!nativeStoreKit.isAvailable()) {
589
+ if (this.debug) console.warn("[Paywallo][Purchase] StoreKit not available");
613
590
  return {
614
591
  success: false,
615
592
  error: new PurchaseError(PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE, "In-app purchases are not available on this device")
616
593
  };
617
594
  }
618
595
  try {
619
- if (this.debug) console.warn("[Paywallo][Purchase] StoreKit purchase starting:", productId);
620
596
  const purchase = await nativeStoreKit.purchase(productId);
621
597
  if (!purchase) {
622
- if (this.debug) console.warn("[Paywallo][Purchase] StoreKit returned null (user cancelled or pending)");
623
598
  return { success: false };
624
599
  }
625
- if (this.debug) console.warn("[Paywallo][Purchase] StoreKit OK \u2014 tx:", purchase.transactionId, "product:", purchase.productId, "receipt length:", purchase.receipt?.length);
626
600
  let validation = null;
627
601
  try {
628
602
  validation = await this.validateWithServer(purchase, productId, options);
@@ -634,14 +608,12 @@ var IAPService = class {
634
608
  };
635
609
  }
636
610
  if (!validation?.success) {
637
- if (this.debug) console.warn("[Paywallo][Purchase] Validation returned failure:", validation?.error || "no validation result");
638
611
  return {
639
612
  success: false,
640
613
  error: new PurchaseError(PURCHASE_ERROR_CODES.VALIDATION_FAILED, validation?.error ? `Server validation: ${validation.error}` : "Server validation failed")
641
614
  };
642
615
  }
643
616
  await this.finishTransaction(purchase.transactionId);
644
- if (this.debug) console.warn("[Paywallo][Purchase] COMPLETE \u2014 validated & finished:", purchase.productId);
645
617
  return { success: true, purchase };
646
618
  } catch (error) {
647
619
  const e = error instanceof PurchaseError ? error : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, error instanceof Error ? error.message : String(error));
@@ -651,20 +623,16 @@ var IAPService = class {
651
623
  }
652
624
  async restore() {
653
625
  if (!nativeStoreKit.isAvailable()) {
654
- if (this.debug) console.warn("[Paywallo][Restore] StoreKit not available");
655
626
  return [];
656
627
  }
657
628
  try {
658
- if (this.debug) console.warn("[Paywallo][Restore] Getting active transactions...");
659
629
  const transactions = await nativeStoreKit.getActiveTransactions();
660
- if (this.debug) console.warn("[Paywallo][Restore] Found", transactions.length, "active transactions");
661
630
  const apiClient = this.getApiClient();
662
631
  const distinctId = PaywalloClient.getDistinctId();
663
632
  const platform = Platform2.OS;
664
633
  const results = await Promise.allSettled(
665
634
  transactions.map((tx) => {
666
635
  const product = this.productsCache.get(tx.productId);
667
- if (this.debug) console.warn("[Paywallo][Restore] Validating tx:", tx.transactionId, "product:", tx.productId);
668
636
  return apiClient.validatePurchase(
669
637
  platform,
670
638
  tx.receipt,
@@ -681,22 +649,18 @@ var IAPService = class {
681
649
  for (let i = 0; i < results.length; i++) {
682
650
  const r = results[i];
683
651
  const tx = transactions[i];
684
- if (this.debug) console.warn("[Paywallo][Restore] Validation:", r.status, r.status === "fulfilled" ? JSON.stringify(r.value) : r.reason?.message);
685
652
  if (r.status === "fulfilled" && r.value.success) {
686
653
  try {
687
654
  await nativeStoreKit.finishTransaction(tx.transactionId);
688
- if (this.debug) console.warn("[Paywallo][Restore] Finished tx:", tx.transactionId);
689
655
  } catch (finishError) {
690
656
  if (this.debug) console.warn("[Paywallo][Restore] Failed to finish tx:", tx.transactionId, finishError instanceof Error ? finishError.message : finishError);
691
657
  }
692
658
  validated.push(tx);
693
- } else {
694
- if (this.debug) console.warn("[Paywallo][Restore] Skipping unvalidated tx:", tx.transactionId);
695
659
  }
696
660
  }
697
661
  return validated;
698
662
  } catch (error) {
699
- if (this.debug) console.warn("[Paywallo][Restore] FAILED:", error instanceof Error ? error.message : error);
663
+ if (this.debug) console.warn("[Paywallo][Restore] \u274C FAILED:", error instanceof Error ? error.message : error);
700
664
  return [];
701
665
  }
702
666
  }
@@ -818,7 +782,6 @@ function usePaywallActions(placement, paywallConfig, onResult, variantKey, campa
818
782
  }
819
783
  onResult({ presented: true, purchased: false, cancelled: false, restored: true });
820
784
  } else {
821
- if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] No purchases to restore");
822
785
  onResult({ presented: true, purchased: false, cancelled: false, restored: false });
823
786
  }
824
787
  } catch (error) {
@@ -961,7 +924,7 @@ function buildPaywallInjectionScript(data) {
961
924
  secondaryProductId: data.secondaryProductId
962
925
  }
963
926
  };
964
- return `(function(){var d=${JSON.stringify(paywallData)},a=0,m=50;function t(){a++;if(window.receiveNativeMessage){window.receiveNativeMessage(d);return;}if(a<m){setTimeout(t,100);}else{console.warn('[Panel WV] FAILED to inject after '+m+' attempts');}}t();})();true;`;
927
+ return `(function(){var d=${JSON.stringify(paywallData)},a=0,m=50;function t(){a++;if(window.receiveNativeMessage){window.receiveNativeMessage(d);return;}if(a<m){setTimeout(t,100);}else{console.warn('[Paywallo WV] FAILED to inject after '+m+' attempts');}}t();})();true;`;
965
928
  }
966
929
  function buildPurchaseStateScript(isPurchasing) {
967
930
  return `if(window.receiveNativeMessage){window.receiveNativeMessage({type:"purchaseState",data:{isPurchasing:${isPurchasing}}});}true;`;
@@ -1120,16 +1083,13 @@ function PaywallModal({
1120
1083
  const openAnim = useRef4(new Animated2.Value(SCREEN_HEIGHT2)).current;
1121
1084
  useEffect3(() => {
1122
1085
  if (visible) {
1123
- if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] PaywallModal opening \u2014 starting slide-up animation (550ms)");
1124
1086
  openAnim.setValue(SCREEN_HEIGHT2);
1125
1087
  Animated2.timing(openAnim, {
1126
1088
  toValue: 0,
1127
1089
  duration: 550,
1128
1090
  easing: Easing.out(Easing.cubic),
1129
1091
  useNativeDriver: true
1130
- }).start(() => {
1131
- if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] PaywallModal slide-up animation completed");
1132
- });
1092
+ }).start();
1133
1093
  }
1134
1094
  }, [visible, openAnim]);
1135
1095
  if (!visible) return null;
@@ -1533,8 +1493,7 @@ function buildConditionalFlagUrl(baseUrl, flagKey, context) {
1533
1493
  }
1534
1494
 
1535
1495
  // src/domains/iap/apiPurchaseMethods.ts
1536
- async function validatePurchase(client, appKey, platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey, debug) {
1537
- if (debug) console.warn("[Paywallo][API] POST /purchases/validate", { platform, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey, receiptLen: receipt?.length });
1496
+ async function validatePurchase(client, appKey, platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey) {
1538
1497
  const response = await client.post(
1539
1498
  `/purchases/validate/${appKey}`,
1540
1499
  {
@@ -1551,7 +1510,6 @@ async function validatePurchase(client, appKey, platform, receipt, productId, tr
1551
1510
  },
1552
1511
  false
1553
1512
  );
1554
- if (debug) console.warn("[Paywallo][API] Validation response:", JSON.stringify(response.data));
1555
1513
  return response.data;
1556
1514
  }
1557
1515
  async function getSubscriptionStatus(client, baseUrl, appKey, distinctId) {
@@ -1629,11 +1587,6 @@ var HttpClient = class {
1629
1587
  if (state.attempt < retryConfig.maxRetries) {
1630
1588
  state.attempt++;
1631
1589
  const delay = this.calculateDelay(state.attempt, retryConfig);
1632
- this.log(`Retrying request (attempt ${state.attempt}/${retryConfig.maxRetries})`, {
1633
- url,
1634
- status: response.status,
1635
- delay
1636
- });
1637
1590
  await this.sleep(delay);
1638
1591
  continue;
1639
1592
  }
@@ -1644,11 +1597,6 @@ var HttpClient = class {
1644
1597
  if (this.isNetworkError(state.lastError) && state.attempt < retryConfig.maxRetries) {
1645
1598
  state.attempt++;
1646
1599
  const delay = this.calculateDelay(state.attempt, retryConfig);
1647
- this.log(`Network error, retrying (attempt ${state.attempt}/${retryConfig.maxRetries})`, {
1648
- url,
1649
- error: state.lastError.message,
1650
- delay
1651
- });
1652
1600
  await this.sleep(delay);
1653
1601
  continue;
1654
1602
  }
@@ -1666,11 +1614,6 @@ var HttpClient = class {
1666
1614
  controller.abort();
1667
1615
  }
1668
1616
  }, timeout);
1669
- this.log("Request starting", {
1670
- url,
1671
- method: options.method,
1672
- headers: options.headers
1673
- });
1674
1617
  try {
1675
1618
  const response = await fetch(url, {
1676
1619
  ...options,
@@ -1683,20 +1626,8 @@ var HttpClient = class {
1683
1626
  data = await response.json();
1684
1627
  } else {
1685
1628
  const textData = await response.text();
1686
- this.log("Non-JSON response received", {
1687
- url,
1688
- status: response.status,
1689
- contentType,
1690
- bodyPreview: textData.substring(0, 200)
1691
- });
1692
1629
  data = textData;
1693
1630
  }
1694
- this.log("Request completed", {
1695
- url,
1696
- status: response.status,
1697
- ok: response.ok,
1698
- contentType
1699
- });
1700
1631
  const headers = {};
1701
1632
  response.headers.forEach((value, key) => {
1702
1633
  headers[key] = value;
@@ -1979,7 +1910,6 @@ var OfflineQueueClass = class {
1979
1910
  this.cleanupExpired();
1980
1911
  this.cleanupTimer = setInterval(() => this.cleanupExpired(), 60 * 60 * 1e3);
1981
1912
  this.initialized = true;
1982
- this.log("OfflineQueue initialized", { queueSize: this.queue.length });
1983
1913
  }
1984
1914
  async loadFromStorage() {
1985
1915
  try {
@@ -2010,7 +1940,6 @@ var OfflineQueueClass = class {
2010
1940
  const before = this.queue.length;
2011
1941
  this.queue = this.queue.filter((item) => Date.now() - item.timestamp < this.config.maxAge);
2012
1942
  if (before !== this.queue.length) {
2013
- this.log("Cleaned up expired items", { removed: before - this.queue.length });
2014
1943
  void this.saveToStorage();
2015
1944
  }
2016
1945
  }
@@ -2027,7 +1956,6 @@ var OfflineQueueClass = class {
2027
1956
  };
2028
1957
  const existingIndex = this.findDuplicateIndex(item);
2029
1958
  if (existingIndex !== -1) {
2030
- this.log("Duplicate item found, updating timestamp", { id: this.queue[existingIndex].id });
2031
1959
  this.queue[existingIndex].timestamp = Date.now();
2032
1960
  await this.saveToStorage();
2033
1961
  return this.queue[existingIndex];
@@ -2035,14 +1963,12 @@ var OfflineQueueClass = class {
2035
1963
  if (this.queue.length >= this.config.maxItems) {
2036
1964
  const removed = this.queue.shift();
2037
1965
  if (removed) {
2038
- this.log("Queue full, evicted oldest item:", removed.url);
2039
1966
  this.emit({ type: "item:evicted", item: removed, queueSize: this.queue.length });
2040
1967
  }
2041
1968
  }
2042
1969
  this.queue.push(item);
2043
1970
  await this.saveToStorage();
2044
1971
  this.emit({ type: "item:added", item, queueSize: this.queue.length });
2045
- this.log("Item enqueued", { id: item.id, url: item.url });
2046
1972
  return item;
2047
1973
  }
2048
1974
  findDuplicateIndex(item) {
@@ -2071,7 +1997,6 @@ var OfflineQueueClass = class {
2071
1997
  this.processingLock = true;
2072
1998
  this.processing = true;
2073
1999
  this.emit({ type: "processing:start", queueSize: this.queue.length });
2074
- this.log("Processing queue", { items: this.queue.length });
2075
2000
  let processed = 0;
2076
2001
  let failed = 0;
2077
2002
  const delayMs = options?.delayBetweenItems ?? 100;
@@ -2088,7 +2013,6 @@ var OfflineQueueClass = class {
2088
2013
  await this.removeItem(item.id);
2089
2014
  processed++;
2090
2015
  this.emit({ type: "item:success", item, queueSize: this.queue.length });
2091
- this.log("Item processed successfully", { id: item.id });
2092
2016
  } else {
2093
2017
  const didFail = await this.handleItemFailure(item, void 0, permanent);
2094
2018
  if (didFail) failed++;
@@ -2103,7 +2027,6 @@ var OfflineQueueClass = class {
2103
2027
  this.processing = false;
2104
2028
  this.processingLock = false;
2105
2029
  this.emit({ type: "processing:end", queueSize: this.queue.length });
2106
- this.log("Queue processing complete", { processed, failed, remaining: this.queue.length });
2107
2030
  return { processed, failed };
2108
2031
  }
2109
2032
  /** Returns true if the item was permanently removed (counted as failed). */
@@ -2116,14 +2039,9 @@ var OfflineQueueClass = class {
2116
2039
  error: error ?? new ClientError(CLIENT_ERROR_CODES.UNKNOWN, permanent ? "Permanent failure" : "Max attempts reached"),
2117
2040
  queueSize: this.queue.length
2118
2041
  });
2119
- this.log(
2120
- permanent ? "Item failed permanently - removed" : "Item failed after max attempts",
2121
- { id: item.id, attempts: item.attempts }
2122
- );
2123
2042
  return true;
2124
2043
  }
2125
2044
  await this.saveToStorage();
2126
- this.log("Item will be retried", { id: item.id, attempts: item.attempts });
2127
2045
  return false;
2128
2046
  }
2129
2047
  sleep(ms) {
@@ -2144,7 +2062,6 @@ var OfflineQueueClass = class {
2144
2062
  async clear() {
2145
2063
  this.queue = [];
2146
2064
  await this.saveToStorage();
2147
- this.log("Queue cleared");
2148
2065
  }
2149
2066
  async clearItemsWithInvalidAppKey(validAppKey) {
2150
2067
  const before = this.queue.length;
@@ -2155,7 +2072,6 @@ var OfflineQueueClass = class {
2155
2072
  const removed = before - this.queue.length;
2156
2073
  if (removed > 0) {
2157
2074
  await this.saveToStorage();
2158
- this.log("Cleared items with invalid app key", { removed, validAppKey });
2159
2075
  }
2160
2076
  return removed;
2161
2077
  }
@@ -2336,6 +2252,8 @@ var ApiCache = class {
2336
2252
  constructor() {
2337
2253
  this.CACHE_TTL = 3e5;
2338
2254
  // 5 minutes
2255
+ this.CACHE_NULL_TTL = 3e4;
2256
+ // 30 seconds — for null/404 variants
2339
2257
  this.MAX_SIZE = 200;
2340
2258
  this.variantCache = /* @__PURE__ */ new Map();
2341
2259
  this.paywallCache = /* @__PURE__ */ new Map();
@@ -2344,27 +2262,34 @@ var ApiCache = class {
2344
2262
  getCached(cache, key) {
2345
2263
  const entry = cache.get(key);
2346
2264
  if (!entry) return void 0;
2347
- if (Date.now() - entry.ts < this.CACHE_TTL) return entry.value;
2265
+ const ttl = entry.ttl ?? this.CACHE_TTL;
2266
+ if (Date.now() - entry.ts < ttl) return entry.value;
2348
2267
  cache.delete(key);
2349
2268
  return void 0;
2350
2269
  }
2351
- setCached(cache, key, value) {
2352
- cache.set(key, { value, ts: Date.now() });
2270
+ setCached(cache, key, value, ttlOverride) {
2271
+ const entry = { value, ts: Date.now() };
2272
+ if (ttlOverride !== void 0) entry.ttl = ttlOverride;
2273
+ cache.set(key, entry);
2353
2274
  }
2354
2275
  evictExpiredEntries(cache) {
2355
2276
  if (cache.size <= this.MAX_SIZE) return;
2356
2277
  const now = Date.now();
2357
2278
  for (const [key, entry] of cache) {
2358
- if (now - entry.ts > this.CACHE_TTL) cache.delete(key);
2279
+ const ttl = entry.ttl ?? this.CACHE_TTL;
2280
+ if (now - entry.ts > ttl) cache.delete(key);
2359
2281
  }
2360
2282
  }
2361
2283
  getVariant(key) {
2362
2284
  return this.getCached(this.variantCache, key);
2363
2285
  }
2364
- setVariant(key, value) {
2365
- this.setCached(this.variantCache, key, value);
2286
+ setVariant(key, value, ttlOverride) {
2287
+ this.setCached(this.variantCache, key, value, ttlOverride);
2366
2288
  this.evictExpiredEntries(this.variantCache);
2367
2289
  }
2290
+ get nullTTL() {
2291
+ return this.CACHE_NULL_TTL;
2292
+ }
2368
2293
  getStaleVariant(key) {
2369
2294
  const entry = this.variantCache.get(key);
2370
2295
  if (entry && Date.now() - entry.ts < 864e5) return entry.value;
@@ -2373,8 +2298,8 @@ var ApiCache = class {
2373
2298
  getPaywall(key) {
2374
2299
  return this.getCached(this.paywallCache, key);
2375
2300
  }
2376
- setPaywall(key, value) {
2377
- this.setCached(this.paywallCache, key, value);
2301
+ setPaywall(key, value, ttlOverride) {
2302
+ this.setCached(this.paywallCache, key, value, ttlOverride);
2378
2303
  this.evictExpiredEntries(this.paywallCache);
2379
2304
  }
2380
2305
  getStalePaywall(key) {
@@ -2400,16 +2325,15 @@ var ApiCache = class {
2400
2325
  var SDK_VERSION = "1.0.0";
2401
2326
  var DEFAULT_BASE_URL = "https://panel.lucasqueiroga.shop";
2402
2327
  var ApiClient = class {
2403
- constructor(appKey, baseUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
2328
+ constructor(appKey, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
2404
2329
  this.cache = new ApiCache();
2405
2330
  this.appKey = appKey;
2406
- this.baseUrl = baseUrl ?? DEFAULT_BASE_URL;
2331
+ this.baseUrl = DEFAULT_BASE_URL;
2407
2332
  this.webUrl = deriveWebUrl(this.baseUrl);
2408
2333
  this.debug = debug;
2409
2334
  this.environment = environment;
2410
2335
  this.offlineQueueEnabled = offlineQueueEnabled;
2411
2336
  this.httpClient = new HttpClient(this.baseUrl, { timeout, debug });
2412
- this.log("ApiClient initialized", { baseUrl: this.baseUrl, environment, offlineQueueEnabled });
2413
2337
  }
2414
2338
  // ─── Infrastructure ──────────────────────────────────────────────────────────
2415
2339
  /** Exposed only for QueueProcessor initialization. Prefer get()/post() for requests. */
@@ -2433,7 +2357,6 @@ var ApiClient = class {
2433
2357
  }
2434
2358
  setEnvironment(environment) {
2435
2359
  this.environment = environment;
2436
- this.log("Environment set to:", environment);
2437
2360
  }
2438
2361
  setDebug(debug) {
2439
2362
  this.debug = debug;
@@ -2463,7 +2386,6 @@ var ApiClient = class {
2463
2386
  }
2464
2387
  // ─── Business methods ────────────────────────────────────────────────────────
2465
2388
  async trackEvent(eventName, distinctId, properties, timestamp) {
2466
- this.log("Tracking event:", eventName);
2467
2389
  await this.postWithQueue("/api/v1/events", {
2468
2390
  eventName,
2469
2391
  distinctId,
@@ -2474,7 +2396,6 @@ var ApiClient = class {
2474
2396
  }
2475
2397
  async identify(distinctId, properties, email) {
2476
2398
  await this.postWithQueue("/api/v1/identify", { distinctId, properties: properties ?? {}, email, platform: Platform3.OS }, "identify");
2477
- this.log("Identity updated:", distinctId);
2478
2399
  }
2479
2400
  async startSession(distinctId, sessionId, platform) {
2480
2401
  await this.postWithQueue("/api/v1/sessions/start", {
@@ -2483,12 +2404,10 @@ var ApiClient = class {
2483
2404
  platform: platform ?? Platform3.OS,
2484
2405
  environment: this.environment.toLowerCase()
2485
2406
  }, `session.start:${sessionId}`);
2486
- this.log("Session started:", sessionId);
2487
2407
  return { success: true };
2488
2408
  }
2489
2409
  async endSession(sessionId, durationSeconds) {
2490
2410
  await this.postWithQueue("/api/v1/sessions/end", { sessionId, durationSeconds }, `session.end:${sessionId}`);
2491
- this.log("Session ended:", sessionId);
2492
2411
  return { success: true };
2493
2412
  }
2494
2413
  async getVariant(flagKey, distinctId) {
@@ -2496,15 +2415,18 @@ var ApiClient = class {
2496
2415
  const hit = this.cache.getVariant(key);
2497
2416
  if (hit !== void 0) return hit;
2498
2417
  try {
2499
- const url = new URL(`${this.baseUrl}/api/v1/flags/${flagKey}`);
2500
- url.searchParams.set("distinctId", distinctId);
2501
- const res = await this.get(url.toString());
2418
+ const res = await this.get(`/api/v1/flags/${flagKey}?distinctId=${encodeURIComponent(distinctId)}`);
2502
2419
  if (res.status === 404) {
2503
2420
  const v = { variant: null };
2504
- this.cache.setVariant(key, v);
2421
+ this.cache.setVariant(key, v, this.cache.nullTTL);
2505
2422
  return v;
2506
2423
  }
2507
- this.log("Got variant:", flagKey, res.data);
2424
+ if (!res.ok) {
2425
+ this.log("Non-OK response for variant:", flagKey, res.status);
2426
+ const stale = this.cache.getStaleVariant(key);
2427
+ if (stale !== void 0) return stale;
2428
+ return { variant: null };
2429
+ }
2508
2430
  this.cache.setVariant(key, res.data);
2509
2431
  return res.data;
2510
2432
  } catch (error) {
@@ -2520,10 +2442,15 @@ var ApiClient = class {
2520
2442
  try {
2521
2443
  const res = await this.get(`/api/v1/paywalls/${placement}`);
2522
2444
  if (res.status === 404) {
2523
- this.cache.setPaywall(placement, null);
2445
+ this.cache.setPaywall(placement, null, this.cache.nullTTL);
2446
+ return null;
2447
+ }
2448
+ if (!res.ok) {
2449
+ this.log("Non-OK response for paywall:", placement, res.status);
2450
+ const stale = this.cache.getStalePaywall(placement);
2451
+ if (stale !== void 0) return stale;
2524
2452
  return null;
2525
2453
  }
2526
- this.log("Got paywall:", placement);
2527
2454
  this.cache.setPaywall(placement, res.data);
2528
2455
  return res.data;
2529
2456
  } catch (error) {
@@ -2572,8 +2499,7 @@ var ApiClient = class {
2572
2499
  country,
2573
2500
  distinctId,
2574
2501
  paywallPlacement,
2575
- variantKey,
2576
- this.debug
2502
+ variantKey
2577
2503
  );
2578
2504
  this.log("Purchase validated:", result.success);
2579
2505
  return result;
@@ -2588,6 +2514,10 @@ var ApiClient = class {
2588
2514
  const url = buildConditionalFlagUrl(this.baseUrl, flagKey, context);
2589
2515
  const response = await this.get(url);
2590
2516
  if (response.status === 404) return { value: false, flagKey };
2517
+ if (!response.ok) {
2518
+ this.log("Non-OK response for conditional flag:", flagKey, response.status);
2519
+ return { value: false, flagKey };
2520
+ }
2591
2521
  this.log("Got conditional flag:", flagKey, response.data.value);
2592
2522
  return { value: response.data.value, flagKey };
2593
2523
  } catch {
@@ -2619,7 +2549,7 @@ var ApiClient = class {
2619
2549
  }
2620
2550
  }
2621
2551
  log(...args) {
2622
- if (this.debug) console.warn("[Panel API]", ...args);
2552
+ if (this.debug) console.warn("[Paywallo API]", ...args);
2623
2553
  }
2624
2554
  };
2625
2555
 
@@ -2945,7 +2875,6 @@ var SessionManager = class {
2945
2875
  this.setupAppStateListener();
2946
2876
  }
2947
2877
  this.initialized = true;
2948
- this.log("SessionManager initialized");
2949
2878
  }
2950
2879
  async startSession() {
2951
2880
  this.ensureInitialized();
@@ -2961,7 +2890,6 @@ var SessionManager = class {
2961
2890
  this.secureStorage.remove(EMERGENCY_PAYWALL_SHOWN_KEY)
2962
2891
  ]);
2963
2892
  await this.trackSessionStart();
2964
- this.log("Session started:", this.sessionId);
2965
2893
  return this.sessionId;
2966
2894
  }
2967
2895
  async endSession() {
@@ -2976,7 +2904,6 @@ var SessionManager = class {
2976
2904
  this.secureStorage.remove(SESSION_ID_KEY),
2977
2905
  this.secureStorage.remove(SESSION_START_KEY)
2978
2906
  ]);
2979
- this.log("Session ended");
2980
2907
  }
2981
2908
  getSessionId() {
2982
2909
  return this.sessionId;
@@ -3111,6 +3038,13 @@ var InstallTracker = class {
3111
3038
  const storage = new SecureStorage(this.debug);
3112
3039
  const alreadyTracked = await storage.get("install_tracked");
3113
3040
  if (alreadyTracked) return;
3041
+ let fallbackTracked = null;
3042
+ try {
3043
+ const AsyncStorage3 = (await import("@react-native-async-storage/async-storage")).default;
3044
+ fallbackTracked = await AsyncStorage3.getItem("@paywallo:install_tracked");
3045
+ } catch {
3046
+ }
3047
+ if (fallbackTracked) return;
3114
3048
  const distinctId = identityManager.getDistinctId();
3115
3049
  const sessionId = sessionManager.getSessionId();
3116
3050
  const installedAt = Date.now();
@@ -3172,12 +3106,13 @@ var InstallTracker = class {
3172
3106
  attStatus: adIds.attStatus
3173
3107
  });
3174
3108
  const stored = await storage.set("install_tracked", String(installedAt));
3175
- if (this.debug) {
3176
- if (stored) {
3177
- console.warn("[Paywallo] Install event tracked");
3178
- } else {
3179
- console.warn("[Paywallo] Install event tracked but flag storage failed \u2014 may re-track on next launch");
3180
- }
3109
+ try {
3110
+ const AsyncStorage3 = (await import("@react-native-async-storage/async-storage")).default;
3111
+ await AsyncStorage3.setItem("@paywallo:install_tracked", String(installedAt));
3112
+ } catch {
3113
+ }
3114
+ if (this.debug && !stored) {
3115
+ console.warn("[Paywallo] Install event tracked but flag storage failed \u2014 may re-track on next launch");
3181
3116
  }
3182
3117
  } catch (error) {
3183
3118
  if (this.debug) {
@@ -3192,7 +3127,7 @@ function isValidEventName(name) {
3192
3127
  if (name.startsWith("$")) return /^\$[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
3193
3128
  return /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/.test(name);
3194
3129
  }
3195
- var PaywalloClientClass = class {
3130
+ var _PaywalloClientClass = class _PaywalloClientClass {
3196
3131
  constructor() {
3197
3132
  this.config = null;
3198
3133
  this.apiClient = null;
@@ -3203,45 +3138,121 @@ var PaywalloClientClass = class {
3203
3138
  this.activeChecker = null;
3204
3139
  this.restoreHandler = null;
3205
3140
  this.lastOnboardingStepTimestamp = null;
3141
+ this.pendingConfig = null;
3142
+ this.networkCleanup = null;
3143
+ this.initAttempts = 0;
3206
3144
  }
3207
3145
  async init(config) {
3208
- if (this.config && this.apiClient) return;
3146
+ console.warn("[Paywallo INIT]", "init() called \u2014 appKey:", config.appKey ? config.appKey.substring(0, 8) + "..." : "MISSING");
3147
+ if (this.config && this.apiClient) {
3148
+ console.warn("[Paywallo INIT]", "Already initialized \u2014 skipping");
3149
+ return;
3150
+ }
3209
3151
  if (this.initPromise) {
3152
+ console.warn("[Paywallo INIT]", "Init already in progress \u2014 awaiting...");
3210
3153
  await this.initPromise;
3154
+ console.warn("[Paywallo INIT]", "Awaited existing init \u2014 done");
3211
3155
  return;
3212
3156
  }
3213
3157
  if (!config.appKey) throw new ClientError(CLIENT_ERROR_CODES.MISSING_APP_KEY, "appKey is required");
3214
- this.initPromise = this.doInit(config);
3158
+ console.warn("[Paywallo INIT]", "Starting fresh init...");
3159
+ this.pendingConfig = config;
3160
+ this.initAttempts = 0;
3161
+ this.initPromise = this.initWithRetry(config);
3215
3162
  try {
3216
3163
  await this.initPromise;
3164
+ console.warn("[Paywallo INIT]", "init() SUCCESS");
3217
3165
  } catch (error) {
3166
+ console.warn("[Paywallo INIT]", "init() FAILED:", error instanceof Error ? error.message : String(error));
3218
3167
  this.initPromise = null;
3219
3168
  this.config = null;
3220
3169
  this.apiClient = null;
3170
+ this.reportInitFailure(config, error, "ALL_RETRIES_EXHAUSTED");
3171
+ this.setupNetworkRecovery(config);
3172
+ throw error;
3173
+ }
3174
+ }
3175
+ async initWithRetry(config) {
3176
+ while (this.initAttempts <= _PaywalloClientClass.MAX_INIT_RETRIES) {
3221
3177
  try {
3222
- const tempClient = new ApiClient(config.appKey, config.baseUrl, config.debug);
3223
- void tempClient.reportError("INIT_FAILED", error instanceof Error ? error.message : String(error));
3224
- } catch {
3178
+ await this.doInit(config);
3179
+ if (this.initAttempts > 0) {
3180
+ this.reportInitSuccess(config, this.initAttempts);
3181
+ }
3182
+ this.cleanupNetworkRecovery();
3183
+ this.pendingConfig = null;
3184
+ return;
3185
+ } catch (error) {
3186
+ this.initAttempts++;
3187
+ if (this.initAttempts > _PaywalloClientClass.MAX_INIT_RETRIES) throw error;
3188
+ const delay = _PaywalloClientClass.RETRY_DELAYS[this.initAttempts - 1] ?? 1e4;
3189
+ if (config.debug) console.warn("[Paywallo]", `Init attempt ${this.initAttempts} failed, retrying in ${delay}ms`, error);
3190
+ await new Promise((resolve) => setTimeout(resolve, delay));
3225
3191
  }
3226
- throw error;
3192
+ }
3193
+ }
3194
+ setupNetworkRecovery(config) {
3195
+ if (this.networkCleanup) return;
3196
+ if (!networkMonitor.isInitialized()) return;
3197
+ this.networkCleanup = networkMonitor.addListener((state) => {
3198
+ if (state !== "online") return;
3199
+ if (this.config && this.apiClient) return;
3200
+ if (config.debug) console.warn("[Paywallo]", "Network recovered \u2014 retrying init");
3201
+ this.initPromise = this.initWithRetry(config);
3202
+ this.initPromise.then(() => {
3203
+ if (config.debug) console.warn("[Paywallo]", "Init succeeded after network recovery");
3204
+ }).catch(() => {
3205
+ this.reportInitFailure(config, null, "NETWORK_RECOVERY_FAILED");
3206
+ });
3207
+ });
3208
+ }
3209
+ cleanupNetworkRecovery() {
3210
+ if (this.networkCleanup) {
3211
+ this.networkCleanup();
3212
+ this.networkCleanup = null;
3213
+ }
3214
+ }
3215
+ reportInitFailure(config, error, reason) {
3216
+ try {
3217
+ const tempClient = new ApiClient(config.appKey, config.debug);
3218
+ void tempClient.reportError("INIT_FAILED", reason, {
3219
+ attempts: this.initAttempts,
3220
+ error: error instanceof Error ? error.message : String(error)
3221
+ });
3222
+ } catch {
3223
+ }
3224
+ }
3225
+ reportInitSuccess(config, attempts) {
3226
+ try {
3227
+ if (this.apiClient) {
3228
+ void this.apiClient.reportError("INIT_RECOVERED", `Succeeded after ${attempts} retries`, { attempts });
3229
+ }
3230
+ } catch {
3227
3231
  }
3228
3232
  }
3229
3233
  async doInit(config) {
3230
3234
  const environment = config.environment ?? (typeof __DEV__ !== "undefined" && __DEV__ ? "Sandbox" : "Production");
3231
3235
  const offlineQueueEnabled = config.offlineQueueEnabled !== false;
3236
+ console.warn("[Paywallo INIT]", "Step 1: networkMonitor + offlineQueue...");
3232
3237
  await Promise.all([
3233
3238
  networkMonitor.initialize({ debug: config.debug }),
3234
3239
  offlineQueue.initialize({ debug: config.debug }).then(
3235
3240
  () => offlineQueue.clearItemsWithInvalidAppKey(config.appKey)
3236
3241
  )
3237
3242
  ]);
3238
- this.apiClient = new ApiClient(config.appKey, config.baseUrl, config.debug, environment, offlineQueueEnabled, config.timeout);
3243
+ console.warn("[Paywallo INIT]", "Step 1 DONE");
3244
+ console.warn("[Paywallo INIT]", "Step 2: ApiClient + queueProcessor + affiliate...");
3245
+ this.apiClient = new ApiClient(config.appKey, config.debug, environment, offlineQueueEnabled, config.timeout);
3239
3246
  queueProcessor.initialize(this.apiClient.getHttpClient(), { debug: config.debug });
3240
3247
  affiliateManager.initialize(this.apiClient, config.debug);
3248
+ console.warn("[Paywallo INIT]", "Step 2 DONE");
3249
+ console.warn("[Paywallo INIT]", "Step 3: identityManager + sessionManager...");
3241
3250
  await Promise.all([
3242
3251
  identityManager.initialize(this.apiClient, config.debug),
3243
3252
  sessionManager.initialize(this.apiClient, config.sessionConfig, config.debug)
3244
3253
  ]);
3254
+ const distinctId = identityManager.getDistinctId();
3255
+ console.warn("[Paywallo INIT]", "Step 3 DONE \u2014 distinctId:", distinctId ? distinctId.substring(0, 8) + "..." : "EMPTY");
3245
3256
  if (config.autoStartSession !== false) {
3246
3257
  sessionManager.startSession().catch(() => {
3247
3258
  if (config.debug) console.warn("[Paywallo]", "Session start failed during init \u2014 continuing");
@@ -3250,6 +3261,7 @@ var PaywalloClientClass = class {
3250
3261
  new InstallTracker(config.debug).trackIfNeeded(this.apiClient, config.requestATT === true).catch(() => {
3251
3262
  });
3252
3263
  this.config = config;
3264
+ console.warn("[Paywallo INIT]", "COMPLETE \u2014 SDK ready, environment:", environment);
3253
3265
  }
3254
3266
  async identify(options) {
3255
3267
  this.ensureInitialized();
@@ -3259,15 +3271,33 @@ var PaywalloClientClass = class {
3259
3271
  const apiClient = this.getApiClientOrThrow();
3260
3272
  const distinctId = identityManager.getDistinctId();
3261
3273
  if (!distinctId) {
3262
- if (this.config?.debug) console.warn("[Paywallo] Skipping event \u2014 no distinctId available");
3274
+ console.warn("[Paywallo TRACK]", "SKIPPED \u2014 no distinctId", eventName);
3263
3275
  return;
3264
3276
  }
3265
3277
  if (!isValidEventName(eventName)) {
3266
3278
  const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
3267
- if (this.config?.debug) console.warn("[Paywallo]", msg);
3268
3279
  throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
3269
3280
  }
3270
3281
  const sessionId = sessionManager.getSessionId();
3282
+ if (eventName === "$purchase_completed") {
3283
+ console.warn("[Paywallo PURCHASE]", "tracking purchase:", JSON.stringify({
3284
+ distinctId: distinctId.substring(0, 8) + "...",
3285
+ productId: options?.properties?.productId,
3286
+ priceUsd: options?.properties?.priceUsd,
3287
+ price: options?.properties?.price,
3288
+ currency: options?.properties?.currency,
3289
+ placement: options?.properties?.placement
3290
+ }));
3291
+ } else if (eventName === "$paywall_viewed" || eventName === "$paywall_closed") {
3292
+ console.warn("[Paywallo PAYWALL]", eventName, JSON.stringify({
3293
+ distinctId: distinctId.substring(0, 8) + "...",
3294
+ placement: options?.properties?.placement,
3295
+ variantKey: options?.properties?.variantKey,
3296
+ timeOnPaywall: options?.properties?.timeOnPaywall
3297
+ }));
3298
+ } else {
3299
+ console.warn("[Paywallo TRACK]", eventName, "distinctId:", distinctId.substring(0, 8) + "...");
3300
+ }
3271
3301
  await apiClient.trackEvent(eventName, distinctId, {
3272
3302
  ...identityManager.getProperties(),
3273
3303
  ...options?.properties,
@@ -3283,7 +3313,6 @@ var PaywalloClientClass = class {
3283
3313
  }
3284
3314
  if (!Number.isInteger(index) || index < 0) {
3285
3315
  const msg = `Invalid stepIndex: "${index}". Must be a non-negative integer.`;
3286
- if (this.config?.debug) console.warn("[Paywallo]", msg);
3287
3316
  throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_STEP_INDEX, msg);
3288
3317
  }
3289
3318
  const now = Date.now();
@@ -3308,7 +3337,6 @@ var PaywalloClientClass = class {
3308
3337
  }
3309
3338
  if (!actionName || typeof actionName !== "string") {
3310
3339
  const msg = `Invalid actionName: "${actionName}". Must be a non-empty string.`;
3311
- if (this.config?.debug) console.warn("[Paywallo]", msg);
3312
3340
  throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_ACTION_NAME, msg);
3313
3341
  }
3314
3342
  const sessionId = sessionManager.getSessionId();
@@ -3320,15 +3348,32 @@ var PaywalloClientClass = class {
3320
3348
  });
3321
3349
  }
3322
3350
  async getVariant(flagKey) {
3323
- const distinctId = identityManager.getDistinctId();
3324
- if (!distinctId) return { variant: null };
3325
- return this.getApiClientOrThrow().getVariant(flagKey, distinctId);
3351
+ try {
3352
+ const distinctId = identityManager.getDistinctId();
3353
+ if (!distinctId) {
3354
+ console.warn("[Paywallo AB]", "getVariant SKIPPED \u2014 no distinctId", flagKey);
3355
+ return { variant: null };
3356
+ }
3357
+ const result = await this.getApiClientOrThrow().getVariant(flagKey, distinctId);
3358
+ console.warn("[Paywallo AB]", `getVariant("${flagKey}") =`, result.variant);
3359
+ return result;
3360
+ } catch (error) {
3361
+ if (this.config?.debug) console.warn("[Paywallo]", "getVariant failed \u2014 returning null", error);
3362
+ if (this.apiClient) void this.apiClient.reportError("GET_VARIANT_FAILED", error instanceof Error ? error.message : String(error));
3363
+ return { variant: null };
3364
+ }
3326
3365
  }
3327
3366
  async getConditionalFlag(flagKey, context) {
3328
- const distinctId = identityManager.getDistinctId();
3329
- if (!distinctId) return false;
3330
- const result = await this.getApiClientOrThrow().getConditionalFlag(flagKey, { distinctId, ...context });
3331
- return result.value;
3367
+ try {
3368
+ const distinctId = identityManager.getDistinctId();
3369
+ if (!distinctId) return false;
3370
+ const result = await this.getApiClientOrThrow().getConditionalFlag(flagKey, { distinctId, ...context });
3371
+ return result.value;
3372
+ } catch (error) {
3373
+ if (this.config?.debug) console.warn("[Paywallo]", "getConditionalFlag failed \u2014 returning false", error);
3374
+ if (this.apiClient) void this.apiClient.reportError("GET_CONDITIONAL_FLAG_FAILED", error instanceof Error ? error.message : String(error));
3375
+ return false;
3376
+ }
3332
3377
  }
3333
3378
  async getPaywall(placement) {
3334
3379
  return this.getApiClientOrThrow().getPaywall(placement);
@@ -3388,9 +3433,12 @@ var PaywalloClientClass = class {
3388
3433
  offlineQueue.dispose();
3389
3434
  networkMonitor.dispose();
3390
3435
  campaignGateService.clearPreloaded();
3436
+ this.cleanupNetworkRecovery();
3391
3437
  this.apiClient = null;
3392
3438
  this.config = null;
3393
3439
  this.initPromise = null;
3440
+ this.pendingConfig = null;
3441
+ this.initAttempts = 0;
3394
3442
  this.paywallPresenter = null;
3395
3443
  this.campaignPresenter = null;
3396
3444
  this.subscriptionGetter = null;
@@ -3506,6 +3554,9 @@ var PaywalloClientClass = class {
3506
3554
  if (!this.config || !this.apiClient) throw new ClientError(CLIENT_ERROR_CODES.NOT_INITIALIZED, "SDK not initialized. Call Paywallo.init() first");
3507
3555
  }
3508
3556
  };
3557
+ _PaywalloClientClass.MAX_INIT_RETRIES = 3;
3558
+ _PaywalloClientClass.RETRY_DELAYS = [2e3, 5e3, 1e4];
3559
+ var PaywalloClientClass = _PaywalloClientClass;
3509
3560
  var PaywalloClient = new PaywalloClientClass();
3510
3561
 
3511
3562
  // src/context/PaywalloContext.ts
@@ -3826,7 +3877,6 @@ var SubscriptionManagerClass = class {
3826
3877
  if (config.cacheTTL) {
3827
3878
  this.cache.setTTL(config.cacheTTL);
3828
3879
  }
3829
- this.log("SubscriptionManager initialized");
3830
3880
  }
3831
3881
  setUserId(userId) {
3832
3882
  if (this.userId !== userId) {
@@ -4159,7 +4209,7 @@ function useProductLoader() {
4159
4209
  for (const p of loaded) map.set(p.productId, p);
4160
4210
  setProducts(map);
4161
4211
  } catch (error) {
4162
- if (PaywalloClient.getConfig()?.debug) console.warn("[Panel] Product load failed:", error);
4212
+ if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] Product load failed:", error);
4163
4213
  } finally {
4164
4214
  setIsLoadingProducts(false);
4165
4215
  }
@@ -4198,7 +4248,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
4198
4248
  clearPreloadedWebView();
4199
4249
  resolvePreloadedPaywall({ presented: true, purchased: true, cancelled: false, restored: false });
4200
4250
  } catch (error) {
4201
- if (PaywalloClient.getConfig()?.debug) console.warn("[Panel] Preloaded purchase error:", error);
4251
+ if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] Preloaded purchase error:", error);
4202
4252
  setShowingPreloadedWebView(false);
4203
4253
  clearPreloadedWebView();
4204
4254
  resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });
@@ -4218,7 +4268,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
4218
4268
  clearPreloadedWebView();
4219
4269
  resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: true });
4220
4270
  } catch (error) {
4221
- if (PaywalloClient.getConfig()?.debug) console.warn("[Panel] Preloaded restore error:", error);
4271
+ if (PaywalloClient.getConfig()?.debug) console.warn("[Paywallo] Preloaded restore error:", error);
4222
4272
  setShowingPreloadedWebView(false);
4223
4273
  clearPreloadedWebView();
4224
4274
  resolvePreloadedPaywall({ presented: true, purchased: false, cancelled: false, restored: false });