@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/LICENSE +1 -1
- package/{MonetySdk.podspec → PaywalloSdk.podspec} +4 -4
- package/README.md +19 -19
- package/android/build.gradle +1 -1
- package/dist/index.d.mts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +202 -152
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +202 -152
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -5
- package/react-native.config.js +3 -3
- package/android/src/main/java/com/monety/sdk/MonetySdkPackage.kt +0 -16
- package/android/src/main/java/com/monety/sdk/PanelStoreKitModule.kt +0 -315
- package/android/src/main/java/com/monety/sdk/PanelWebView.kt +0 -74
- package/android/src/main/java/com/monety/sdk/PanelWebViewManager.kt +0 -52
- package/ios/PanelStoreKit.m +0 -21
- package/ios/PanelStoreKit.swift +0 -245
- package/ios/PanelWebView.h +0 -15
- package/ios/PanelWebView.m +0 -182
- package/ios/PanelWebViewManager.m +0 -41
- package/ios/PanelWebViewModule.h +0 -8
- package/ios/PanelWebViewModule.m +0 -42
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
|
-
|
|
137
|
-
|
|
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
|
|
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
|
|
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
|
|
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('[
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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("[
|
|
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
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
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
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
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("[
|
|
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("[
|
|
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("[
|
|
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 });
|