@virex-tech/paywallo-sdk 1.4.0 → 1.5.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/android/src/main/java/com/paywallo/sdk/PaywalloStoreKitModule.kt +17 -7
- package/dist/index.d.mts +12 -107
- package/dist/index.d.ts +12 -107
- package/dist/index.js +291 -287
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +287 -278
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloFBBridge.swift +1 -1
- package/ios/PaywalloStoreKit.swift +17 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -52,10 +52,7 @@ var init_uuid = __esm({
|
|
|
52
52
|
// src/index.ts
|
|
53
53
|
var index_exports = {};
|
|
54
54
|
__export(index_exports, {
|
|
55
|
-
AFFILIATE_ERROR_CODES: () => AFFILIATE_ERROR_CODES,
|
|
56
55
|
ANALYTICS_ERROR_CODES: () => ANALYTICS_ERROR_CODES,
|
|
57
|
-
AffiliateError: () => AffiliateError,
|
|
58
|
-
AffiliateManager: () => AffiliateManager,
|
|
59
56
|
AnalyticsError: () => AnalyticsError,
|
|
60
57
|
ApiClient: () => ApiClient,
|
|
61
58
|
CAMPAIGN_ERROR_CODES: () => CAMPAIGN_ERROR_CODES,
|
|
@@ -73,7 +70,6 @@ __export(index_exports, {
|
|
|
73
70
|
PaywallError: () => PaywallError,
|
|
74
71
|
PaywallModal: () => PaywallModal,
|
|
75
72
|
Paywallo: () => Paywallo,
|
|
76
|
-
PaywalloAffiliate: () => PaywalloAffiliate,
|
|
77
73
|
PaywalloClient: () => PaywalloClient,
|
|
78
74
|
PaywalloContext: () => PaywalloContext,
|
|
79
75
|
PaywalloError: () => PaywalloError,
|
|
@@ -83,7 +79,6 @@ __export(index_exports, {
|
|
|
83
79
|
SessionError: () => SessionError,
|
|
84
80
|
SessionManager: () => SessionManager,
|
|
85
81
|
SubscriptionCache: () => SubscriptionCache,
|
|
86
|
-
affiliateManager: () => affiliateManager,
|
|
87
82
|
createPurchaseError: () => createPurchaseError,
|
|
88
83
|
default: () => index_default,
|
|
89
84
|
detectDeviceLanguage: () => detectDeviceLanguage,
|
|
@@ -308,6 +303,7 @@ var SecureStorage = class {
|
|
|
308
303
|
var secureStorage = new SecureStorage();
|
|
309
304
|
|
|
310
305
|
// src/domains/identity/IdentityManager.ts
|
|
306
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
311
307
|
var DEVICE_ID_KEY = "device_id";
|
|
312
308
|
var ANON_ID_KEY = "anon_id";
|
|
313
309
|
var USER_EMAIL_KEY = "user_email";
|
|
@@ -364,8 +360,15 @@ var IdentityManager = class {
|
|
|
364
360
|
}
|
|
365
361
|
}
|
|
366
362
|
if (email) {
|
|
367
|
-
|
|
368
|
-
|
|
363
|
+
if (!EMAIL_REGEX.test(email)) {
|
|
364
|
+
if (this.debug) {
|
|
365
|
+
console.warn("[Paywallo] Invalid email format, skipping email field");
|
|
366
|
+
}
|
|
367
|
+
email = void 0;
|
|
368
|
+
} else {
|
|
369
|
+
this.email = email;
|
|
370
|
+
await this.secureStorage.set(USER_EMAIL_KEY, email);
|
|
371
|
+
}
|
|
369
372
|
}
|
|
370
373
|
if (properties) {
|
|
371
374
|
this.properties = { ...this.properties, ...properties };
|
|
@@ -696,17 +699,25 @@ var IAPService = class {
|
|
|
696
699
|
error: new PurchaseError(PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE, "In-app purchases are not available on this device")
|
|
697
700
|
};
|
|
698
701
|
}
|
|
702
|
+
const debug = PaywalloClient.getConfig()?.debug;
|
|
703
|
+
if (debug) console.info(`[Paywallo PURCHASE] starting ${productId}`);
|
|
699
704
|
try {
|
|
700
705
|
const purchase = await nativeStoreKit.purchase(productId);
|
|
701
706
|
if (!purchase) {
|
|
707
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} cancelled`);
|
|
702
708
|
return { success: false };
|
|
703
709
|
}
|
|
710
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} approved`, { transactionId: purchase.transactionId });
|
|
704
711
|
await this.finishTransaction(purchase.transactionId);
|
|
705
|
-
|
|
706
|
-
|
|
712
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} finished`);
|
|
713
|
+
this.validateWithServer(purchase, productId, options).then(() => {
|
|
714
|
+
if (debug) console.info(`[Paywallo PURCHASE] ${productId} server validated`);
|
|
715
|
+
}).catch((err) => {
|
|
716
|
+
if (debug) console.warn("[Paywallo PURCHASE] background validation failed", err);
|
|
707
717
|
});
|
|
708
718
|
return { success: true, purchase };
|
|
709
719
|
} catch (error) {
|
|
720
|
+
if (debug) console.warn(`[Paywallo PURCHASE] ${productId} failed`, error);
|
|
710
721
|
const e = error instanceof PurchaseError ? error : new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, error instanceof Error ? error.message : String(error));
|
|
711
722
|
return { success: false, error: e };
|
|
712
723
|
}
|
|
@@ -1564,227 +1575,6 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
1564
1575
|
return { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady, handlePreloadedClose, setShowingPreloadedWebView, presentedAtRef };
|
|
1565
1576
|
}
|
|
1566
1577
|
|
|
1567
|
-
// src/domains/affiliate/AffiliateError.ts
|
|
1568
|
-
var AffiliateError = class extends PaywalloError {
|
|
1569
|
-
constructor(code, message) {
|
|
1570
|
-
super("affiliate", code, message);
|
|
1571
|
-
this.name = "AffiliateError";
|
|
1572
|
-
}
|
|
1573
|
-
};
|
|
1574
|
-
var AFFILIATE_ERROR_CODES = {
|
|
1575
|
-
NOT_INITIALIZED: "AFFILIATE_NOT_INITIALIZED",
|
|
1576
|
-
COUPON_REGISTER_FAILED: "AFFILIATE_COUPON_REGISTER_FAILED",
|
|
1577
|
-
COUPON_APPLY_FAILED: "AFFILIATE_COUPON_APPLY_FAILED",
|
|
1578
|
-
BALANCE_FETCH_FAILED: "AFFILIATE_BALANCE_FETCH_FAILED",
|
|
1579
|
-
WITHDRAWAL_FAILED: "AFFILIATE_WITHDRAWAL_FAILED",
|
|
1580
|
-
NETWORK_ERROR: "AFFILIATE_NETWORK_ERROR"
|
|
1581
|
-
};
|
|
1582
|
-
|
|
1583
|
-
// src/domains/affiliate/affiliateHttp.ts
|
|
1584
|
-
function buildQueryString(params) {
|
|
1585
|
-
if (!params) return "";
|
|
1586
|
-
const entries = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null);
|
|
1587
|
-
if (entries.length === 0) return "";
|
|
1588
|
-
return `?${entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&")}`;
|
|
1589
|
-
}
|
|
1590
|
-
async function affiliateGet(apiClient, path, params) {
|
|
1591
|
-
const response = await apiClient.get(`${path}${buildQueryString(params)}`);
|
|
1592
|
-
return response.data;
|
|
1593
|
-
}
|
|
1594
|
-
async function affiliatePost(apiClient, path, body) {
|
|
1595
|
-
const response = await apiClient.post(path, body);
|
|
1596
|
-
return response.data;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
// src/domains/affiliate/affiliateDateMappers.ts
|
|
1600
|
-
function mapRawCoupon(raw) {
|
|
1601
|
-
return { code: raw.code, status: raw.status, createdAt: new Date(raw.createdAt) };
|
|
1602
|
-
}
|
|
1603
|
-
function mapRawCommission(raw) {
|
|
1604
|
-
return { ...raw, createdAt: new Date(raw.createdAt) };
|
|
1605
|
-
}
|
|
1606
|
-
function mapRawWithdrawal(raw) {
|
|
1607
|
-
return { ...raw, createdAt: new Date(raw.createdAt) };
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
// src/domains/affiliate/AffiliateManager.ts
|
|
1611
|
-
var AffiliateManager = class {
|
|
1612
|
-
constructor() {
|
|
1613
|
-
this.apiClient = null;
|
|
1614
|
-
this.debug = false;
|
|
1615
|
-
}
|
|
1616
|
-
initialize(apiClient, debug = false) {
|
|
1617
|
-
this.apiClient = apiClient;
|
|
1618
|
-
this.debug = debug;
|
|
1619
|
-
this.log("AffiliateManager initialized");
|
|
1620
|
-
}
|
|
1621
|
-
async registerCoupon(code) {
|
|
1622
|
-
this.ensureInitialized();
|
|
1623
|
-
const distinctId = identityManager.getDistinctId();
|
|
1624
|
-
try {
|
|
1625
|
-
const response = await this.post("/api/v1/affiliate/register-coupon", {
|
|
1626
|
-
code,
|
|
1627
|
-
distinctId
|
|
1628
|
-
});
|
|
1629
|
-
if (response.success && response.coupon) {
|
|
1630
|
-
this.log("Coupon registered:", code);
|
|
1631
|
-
return { success: true, coupon: mapRawCoupon(response.coupon) };
|
|
1632
|
-
}
|
|
1633
|
-
return {
|
|
1634
|
-
success: false,
|
|
1635
|
-
error: response.error
|
|
1636
|
-
};
|
|
1637
|
-
} catch (error) {
|
|
1638
|
-
this.log("Failed to register coupon:", error);
|
|
1639
|
-
return {
|
|
1640
|
-
success: false,
|
|
1641
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
async applyCoupon(code) {
|
|
1646
|
-
this.ensureInitialized();
|
|
1647
|
-
const distinctId = identityManager.getDistinctId();
|
|
1648
|
-
try {
|
|
1649
|
-
const response = await this.post("/api/v1/affiliate/apply-coupon", {
|
|
1650
|
-
code,
|
|
1651
|
-
distinctId
|
|
1652
|
-
});
|
|
1653
|
-
if (response.success) {
|
|
1654
|
-
this.log("Coupon applied:", code);
|
|
1655
|
-
}
|
|
1656
|
-
return response;
|
|
1657
|
-
} catch (error) {
|
|
1658
|
-
this.log("Failed to apply coupon:", error);
|
|
1659
|
-
return {
|
|
1660
|
-
success: false,
|
|
1661
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1662
|
-
};
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
async getMyCoupon() {
|
|
1666
|
-
this.ensureInitialized();
|
|
1667
|
-
const distinctId = identityManager.getDistinctId();
|
|
1668
|
-
try {
|
|
1669
|
-
const response = await this.get("/api/v1/affiliate/my-coupon", { distinctId });
|
|
1670
|
-
if (response.coupon) {
|
|
1671
|
-
return { coupon: mapRawCoupon(response.coupon) };
|
|
1672
|
-
}
|
|
1673
|
-
return { coupon: null };
|
|
1674
|
-
} catch (error) {
|
|
1675
|
-
this.log("Failed to get my coupon:", error);
|
|
1676
|
-
return { coupon: null };
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
async getAppliedCoupon() {
|
|
1680
|
-
this.ensureInitialized();
|
|
1681
|
-
const distinctId = identityManager.getDistinctId();
|
|
1682
|
-
try {
|
|
1683
|
-
const response = await this.get("/api/v1/affiliate/applied-coupon", { distinctId });
|
|
1684
|
-
return response;
|
|
1685
|
-
} catch (error) {
|
|
1686
|
-
this.log("Failed to get applied coupon:", error);
|
|
1687
|
-
return { coupon: null };
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
async getBalance() {
|
|
1691
|
-
this.ensureInitialized();
|
|
1692
|
-
const distinctId = identityManager.getDistinctId();
|
|
1693
|
-
try {
|
|
1694
|
-
const response = await this.get("/api/v1/affiliate/balance", {
|
|
1695
|
-
distinctId
|
|
1696
|
-
});
|
|
1697
|
-
return response;
|
|
1698
|
-
} catch (error) {
|
|
1699
|
-
this.log("Failed to get balance:", error);
|
|
1700
|
-
return {
|
|
1701
|
-
total: 0,
|
|
1702
|
-
pending: 0,
|
|
1703
|
-
available: 0,
|
|
1704
|
-
withdrawn: 0
|
|
1705
|
-
};
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
async getCommissions() {
|
|
1709
|
-
this.ensureInitialized();
|
|
1710
|
-
const distinctId = identityManager.getDistinctId();
|
|
1711
|
-
try {
|
|
1712
|
-
const response = await this.get("/api/v1/affiliate/commissions", { distinctId });
|
|
1713
|
-
return response.commissions.map(mapRawCommission);
|
|
1714
|
-
} catch (error) {
|
|
1715
|
-
this.log("Failed to get commissions:", error);
|
|
1716
|
-
return [];
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
async requestWithdrawal(amount) {
|
|
1720
|
-
this.ensureInitialized();
|
|
1721
|
-
const distinctId = identityManager.getDistinctId();
|
|
1722
|
-
try {
|
|
1723
|
-
const response = await this.post("/api/v1/affiliate/withdraw", {
|
|
1724
|
-
amount,
|
|
1725
|
-
distinctId
|
|
1726
|
-
});
|
|
1727
|
-
if (response.success && response.withdrawal) {
|
|
1728
|
-
this.log("Withdrawal requested:", amount);
|
|
1729
|
-
return { success: true, withdrawal: mapRawWithdrawal(response.withdrawal) };
|
|
1730
|
-
}
|
|
1731
|
-
return {
|
|
1732
|
-
success: false,
|
|
1733
|
-
error: response.error
|
|
1734
|
-
};
|
|
1735
|
-
} catch (error) {
|
|
1736
|
-
this.log("Failed to request withdrawal:", error);
|
|
1737
|
-
return {
|
|
1738
|
-
success: false,
|
|
1739
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1740
|
-
};
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
async getWithdrawals() {
|
|
1744
|
-
this.ensureInitialized();
|
|
1745
|
-
const distinctId = identityManager.getDistinctId();
|
|
1746
|
-
try {
|
|
1747
|
-
const response = await this.get("/api/v1/affiliate/withdrawals", { distinctId });
|
|
1748
|
-
return response.withdrawals.map(mapRawWithdrawal);
|
|
1749
|
-
} catch (error) {
|
|
1750
|
-
this.log("Failed to get withdrawals:", error);
|
|
1751
|
-
return [];
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
async get(path, params) {
|
|
1755
|
-
this.ensureInitialized();
|
|
1756
|
-
return affiliateGet(this.apiClient, path, params);
|
|
1757
|
-
}
|
|
1758
|
-
async post(path, body) {
|
|
1759
|
-
this.ensureInitialized();
|
|
1760
|
-
return affiliatePost(this.apiClient, path, body);
|
|
1761
|
-
}
|
|
1762
|
-
ensureInitialized() {
|
|
1763
|
-
if (!this.apiClient) {
|
|
1764
|
-
throw new AffiliateError(
|
|
1765
|
-
AFFILIATE_ERROR_CODES.NOT_INITIALIZED,
|
|
1766
|
-
"AffiliateManager not initialized. Call initialize() first"
|
|
1767
|
-
);
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
log(...args) {
|
|
1771
|
-
if (this.debug) console.log("[Paywallo:Affiliate]", ...args);
|
|
1772
|
-
}
|
|
1773
|
-
};
|
|
1774
|
-
var affiliateManager = new AffiliateManager();
|
|
1775
|
-
|
|
1776
|
-
// src/domains/affiliate/PaywalloAffiliate.ts
|
|
1777
|
-
var PaywalloAffiliate = {
|
|
1778
|
-
registerCoupon: (code) => affiliateManager.registerCoupon(code),
|
|
1779
|
-
applyCoupon: (code) => affiliateManager.applyCoupon(code),
|
|
1780
|
-
getMyCoupon: () => affiliateManager.getMyCoupon(),
|
|
1781
|
-
getAppliedCoupon: () => affiliateManager.getAppliedCoupon(),
|
|
1782
|
-
getBalance: () => affiliateManager.getBalance(),
|
|
1783
|
-
getCommissions: () => affiliateManager.getCommissions(),
|
|
1784
|
-
requestWithdrawal: (amount) => affiliateManager.requestWithdrawal(amount),
|
|
1785
|
-
getWithdrawals: () => affiliateManager.getWithdrawals()
|
|
1786
|
-
};
|
|
1787
|
-
|
|
1788
1578
|
// src/domains/subscription/SubscriptionCache.ts
|
|
1789
1579
|
var LEGACY_CACHE_KEY = "subscription_cache";
|
|
1790
1580
|
var CACHE_KEY_PREFIX = "subscription_cache:";
|
|
@@ -1894,9 +1684,6 @@ var SubscriptionCache = class {
|
|
|
1894
1684
|
};
|
|
1895
1685
|
var subscriptionCache = new SubscriptionCache();
|
|
1896
1686
|
|
|
1897
|
-
// src/domains/subscription/SubscriptionManager.ts
|
|
1898
|
-
var import_react_native7 = require("react-native");
|
|
1899
|
-
|
|
1900
1687
|
// src/domains/session/SessionError.ts
|
|
1901
1688
|
var SessionError = class extends PaywalloError {
|
|
1902
1689
|
constructor(code, message) {
|
|
@@ -1984,11 +1771,10 @@ var SubscriptionManagerClass = class {
|
|
|
1984
1771
|
if (!this.config) {
|
|
1985
1772
|
return this.getEmptyStatus();
|
|
1986
1773
|
}
|
|
1987
|
-
const url = new URL(`${this.config.serverUrl}/
|
|
1774
|
+
const url = new URL(`${this.config.serverUrl}/purchases/status/${encodeURIComponent(this.config.appKey)}`);
|
|
1988
1775
|
if (this.userId) {
|
|
1989
|
-
url.searchParams.set("
|
|
1776
|
+
url.searchParams.set("distinctId", this.userId);
|
|
1990
1777
|
}
|
|
1991
|
-
url.searchParams.set("platform", import_react_native7.Platform.OS);
|
|
1992
1778
|
const response = await fetch(url.toString(), {
|
|
1993
1779
|
method: "GET",
|
|
1994
1780
|
headers: {
|
|
@@ -2043,7 +1829,7 @@ var SubscriptionManagerClass = class {
|
|
|
2043
1829
|
var subscriptionManager = new SubscriptionManagerClass();
|
|
2044
1830
|
|
|
2045
1831
|
// src/core/ApiClient.ts
|
|
2046
|
-
var
|
|
1832
|
+
var import_react_native8 = require("react-native");
|
|
2047
1833
|
|
|
2048
1834
|
// src/core/apiUrlUtils.ts
|
|
2049
1835
|
var DEFAULT_WEB_URL = "https://paywallo.com.br";
|
|
@@ -2293,7 +2079,7 @@ var HttpClient = class {
|
|
|
2293
2079
|
};
|
|
2294
2080
|
|
|
2295
2081
|
// src/core/network/NetworkMonitor.ts
|
|
2296
|
-
var
|
|
2082
|
+
var import_react_native7 = require("react-native");
|
|
2297
2083
|
|
|
2298
2084
|
// src/core/network/types.ts
|
|
2299
2085
|
var DEFAULT_NETWORK_CONFIG = {
|
|
@@ -2330,7 +2116,7 @@ var NetworkMonitorClass = class {
|
|
|
2330
2116
|
}, this.config.checkInterval);
|
|
2331
2117
|
}
|
|
2332
2118
|
setupAppStateListener() {
|
|
2333
|
-
this.appStateSubscription =
|
|
2119
|
+
this.appStateSubscription = import_react_native7.AppState.addEventListener("change", (state) => {
|
|
2334
2120
|
if (state === "active") {
|
|
2335
2121
|
void this.checkConnectivity();
|
|
2336
2122
|
}
|
|
@@ -2726,9 +2512,78 @@ var QueueProcessorClass = class {
|
|
|
2726
2512
|
this.log("Offline, skipping queue processing");
|
|
2727
2513
|
return { processed: 0, failed: 0 };
|
|
2728
2514
|
}
|
|
2729
|
-
|
|
2515
|
+
const allItems = offlineQueue.getQueue();
|
|
2516
|
+
const eventItems = allItems.filter(
|
|
2517
|
+
(i) => i.url.includes("/api/v1/events") && !i.url.includes("/batch")
|
|
2518
|
+
);
|
|
2519
|
+
const eventItemIds = new Set(eventItems.map((i) => i.id));
|
|
2520
|
+
const { processed: batchProcessed, failed: batchFailed, retryIds } = await this.processEventBatches(eventItems);
|
|
2521
|
+
const batchResult = { processed: batchProcessed, failed: batchFailed };
|
|
2522
|
+
const individualResult = await offlineQueue.processQueue(async (item) => {
|
|
2523
|
+
if (eventItemIds.has(item.id)) {
|
|
2524
|
+
if (retryIds.has(item.id)) {
|
|
2525
|
+
return { success: false, permanent: false };
|
|
2526
|
+
}
|
|
2527
|
+
return { success: true, permanent: false };
|
|
2528
|
+
}
|
|
2730
2529
|
return this.processItem(item);
|
|
2731
2530
|
});
|
|
2531
|
+
this.log("Queue processing complete", {
|
|
2532
|
+
batchProcessed: batchResult.processed,
|
|
2533
|
+
batchFailed: batchResult.failed,
|
|
2534
|
+
individualProcessed: individualResult.processed,
|
|
2535
|
+
individualFailed: individualResult.failed
|
|
2536
|
+
});
|
|
2537
|
+
return {
|
|
2538
|
+
processed: batchResult.processed + individualResult.processed,
|
|
2539
|
+
failed: batchResult.failed + individualResult.failed
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
async processEventBatches(eventItems) {
|
|
2543
|
+
if (eventItems.length === 0 || !this.httpClient) {
|
|
2544
|
+
return { processed: 0, failed: 0, retryIds: /* @__PURE__ */ new Set() };
|
|
2545
|
+
}
|
|
2546
|
+
const BATCH_SIZE = 50;
|
|
2547
|
+
let processed = 0;
|
|
2548
|
+
let failed = 0;
|
|
2549
|
+
const retryIds = /* @__PURE__ */ new Set();
|
|
2550
|
+
for (let i = 0; i < eventItems.length; i += BATCH_SIZE) {
|
|
2551
|
+
const batch = eventItems.slice(i, i + BATCH_SIZE);
|
|
2552
|
+
const bodies = batch.map((item) => item.body);
|
|
2553
|
+
const headers = batch[0].headers;
|
|
2554
|
+
this.log("Sending event batch", { size: batch.length, batchIndex: Math.floor(i / BATCH_SIZE) });
|
|
2555
|
+
const response = await this.httpClient.request("/api/v1/events/batch", {
|
|
2556
|
+
method: "POST",
|
|
2557
|
+
body: { events: bodies },
|
|
2558
|
+
headers,
|
|
2559
|
+
skipRetry: false
|
|
2560
|
+
});
|
|
2561
|
+
if (response.ok) {
|
|
2562
|
+
for (const item of batch) {
|
|
2563
|
+
await offlineQueue.removeItem(item.id);
|
|
2564
|
+
processed++;
|
|
2565
|
+
}
|
|
2566
|
+
this.log("Event batch processed successfully", { size: batch.length });
|
|
2567
|
+
} else if (response.status >= 400 && response.status < 500) {
|
|
2568
|
+
for (const item of batch) {
|
|
2569
|
+
await offlineQueue.removeItem(item.id);
|
|
2570
|
+
failed++;
|
|
2571
|
+
}
|
|
2572
|
+
this.log("Event batch failed permanently (4xx) - removing from queue", {
|
|
2573
|
+
status: response.status,
|
|
2574
|
+
size: batch.length
|
|
2575
|
+
});
|
|
2576
|
+
} else {
|
|
2577
|
+
for (const item of batch) {
|
|
2578
|
+
retryIds.add(item.id);
|
|
2579
|
+
}
|
|
2580
|
+
this.log("Event batch failed with server error - will retry", {
|
|
2581
|
+
status: response.status,
|
|
2582
|
+
size: batch.length
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return { processed, failed, retryIds };
|
|
2732
2587
|
}
|
|
2733
2588
|
async processItem(item) {
|
|
2734
2589
|
if (!this.httpClient) {
|
|
@@ -2879,10 +2734,14 @@ var ApiCache = class {
|
|
|
2879
2734
|
};
|
|
2880
2735
|
|
|
2881
2736
|
// src/core/ApiClient.ts
|
|
2882
|
-
var SDK_VERSION = "1.
|
|
2737
|
+
var SDK_VERSION = "1.5.0";
|
|
2883
2738
|
var _ApiClient = class _ApiClient {
|
|
2884
2739
|
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2885
2740
|
this.cache = new ApiCache();
|
|
2741
|
+
this.eventBatch = [];
|
|
2742
|
+
this.batchTimer = null;
|
|
2743
|
+
this.BATCH_MAX_SIZE = 10;
|
|
2744
|
+
this.BATCH_FLUSH_MS = 5e3;
|
|
2886
2745
|
this.appKey = appKey;
|
|
2887
2746
|
this.baseUrl = apiUrl;
|
|
2888
2747
|
this.webUrl = deriveWebUrl(this.baseUrl);
|
|
@@ -2935,30 +2794,79 @@ var _ApiClient = class _ApiClient {
|
|
|
2935
2794
|
message,
|
|
2936
2795
|
context,
|
|
2937
2796
|
sdkVersion: SDK_VERSION,
|
|
2938
|
-
platform:
|
|
2797
|
+
platform: import_react_native8.Platform.OS
|
|
2939
2798
|
}, true);
|
|
2940
2799
|
} catch (err) {
|
|
2941
2800
|
if (this.debug) console.warn("[Paywallo:ApiClient] reportError failed", err);
|
|
2942
2801
|
}
|
|
2943
2802
|
}
|
|
2944
2803
|
async trackEvent(eventName, distinctId, properties, timestamp) {
|
|
2945
|
-
|
|
2804
|
+
const EVENT_NAME_REGEX = /^(\$[a-zA-Z0-9_]+|[a-z][a-z0-9_]*)$/;
|
|
2805
|
+
if (!EVENT_NAME_REGEX.test(eventName)) {
|
|
2806
|
+
if (this.debug) {
|
|
2807
|
+
console.warn(`[Paywallo] Invalid event name "${eventName}". Must be snake_case or start with $`);
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
const event = {
|
|
2946
2811
|
eventName,
|
|
2947
2812
|
distinctId,
|
|
2948
|
-
properties: { ...properties, platform:
|
|
2813
|
+
properties: { ...properties, platform: import_react_native8.Platform.OS },
|
|
2949
2814
|
timestamp: timestamp ?? Date.now(),
|
|
2950
2815
|
environment: this.environment.toLowerCase()
|
|
2951
|
-
}
|
|
2816
|
+
};
|
|
2817
|
+
this.eventBatch.push(event);
|
|
2818
|
+
if (this.eventBatch.length >= this.BATCH_MAX_SIZE) {
|
|
2819
|
+
if (this.batchTimer !== null) {
|
|
2820
|
+
clearTimeout(this.batchTimer);
|
|
2821
|
+
this.batchTimer = null;
|
|
2822
|
+
}
|
|
2823
|
+
await this.flushEventBatch();
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
if (this.batchTimer !== null) {
|
|
2827
|
+
clearTimeout(this.batchTimer);
|
|
2828
|
+
}
|
|
2829
|
+
this.batchTimer = setTimeout(() => {
|
|
2830
|
+
this.batchTimer = null;
|
|
2831
|
+
void this.flushEventBatch();
|
|
2832
|
+
}, this.BATCH_FLUSH_MS);
|
|
2833
|
+
}
|
|
2834
|
+
async flushEventBatch() {
|
|
2835
|
+
if (this.eventBatch.length === 0) return;
|
|
2836
|
+
const batch = this.eventBatch.splice(0, this.eventBatch.length);
|
|
2837
|
+
if (this.batchTimer !== null) {
|
|
2838
|
+
clearTimeout(this.batchTimer);
|
|
2839
|
+
this.batchTimer = null;
|
|
2840
|
+
}
|
|
2841
|
+
try {
|
|
2842
|
+
await this.postWithQueue(
|
|
2843
|
+
"/api/v1/events/batch",
|
|
2844
|
+
{ events: batch },
|
|
2845
|
+
`event_batch:${batch.length}`
|
|
2846
|
+
);
|
|
2847
|
+
} catch (error) {
|
|
2848
|
+
this.log("Batch send failed, falling back to individual sends:", error);
|
|
2849
|
+
for (const event of batch) {
|
|
2850
|
+
await this.postWithQueue(
|
|
2851
|
+
"/api/v1/events",
|
|
2852
|
+
event,
|
|
2853
|
+
`event:${event.eventName}`
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2952
2857
|
}
|
|
2953
2858
|
async identify(distinctId, properties, email, deviceId) {
|
|
2954
|
-
await this.postWithQueue("/api/v1/identify", { distinctId, properties: properties ?? {}, email, platform:
|
|
2859
|
+
await this.postWithQueue("/api/v1/identify", { distinctId, properties: properties ?? {}, email, platform: import_react_native8.Platform.OS, ...deviceId && { deviceId } }, "identify");
|
|
2955
2860
|
}
|
|
2956
|
-
async startSession(distinctId, sessionId, platform) {
|
|
2861
|
+
async startSession(distinctId, sessionId, platform, appVersion, deviceModel, osVersion) {
|
|
2957
2862
|
await this.postWithQueue("/api/v1/sessions/start", {
|
|
2958
2863
|
distinctId,
|
|
2959
2864
|
sessionId,
|
|
2960
|
-
platform: platform ??
|
|
2961
|
-
environment: this.environment.toLowerCase()
|
|
2865
|
+
platform: platform ?? import_react_native8.Platform.OS,
|
|
2866
|
+
environment: this.environment.toLowerCase(),
|
|
2867
|
+
appVersion: appVersion ?? "unknown",
|
|
2868
|
+
deviceModel: deviceModel ?? "unknown",
|
|
2869
|
+
osVersion: osVersion ?? String(import_react_native8.Platform.Version)
|
|
2962
2870
|
}, `session.start:${sessionId}`);
|
|
2963
2871
|
return { success: true };
|
|
2964
2872
|
}
|
|
@@ -2978,6 +2886,7 @@ var _ApiClient = class _ApiClient {
|
|
|
2978
2886
|
try {
|
|
2979
2887
|
const res = await this.get(`/api/v1/flags/${flagKey}?distinctId=${encodeURIComponent(distinctId)}`);
|
|
2980
2888
|
if (res.status === 404) {
|
|
2889
|
+
this.log("Flag not found (404):", flagKey);
|
|
2981
2890
|
const v = { variant: null };
|
|
2982
2891
|
this.cache.setVariant(key, v, this.cache.nullTTL);
|
|
2983
2892
|
return v;
|
|
@@ -3004,6 +2913,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3004
2913
|
try {
|
|
3005
2914
|
const res = await this.get(`/api/v1/paywalls/${placement}`);
|
|
3006
2915
|
if (res.status === 404) {
|
|
2916
|
+
this.log("Paywall not found (404):", placement);
|
|
3007
2917
|
this.cache.setPaywall(placement, null, this.cache.nullTTL);
|
|
3008
2918
|
return null;
|
|
3009
2919
|
}
|
|
@@ -3055,6 +2965,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3055
2965
|
try {
|
|
3056
2966
|
const res = await this.get(`/campaigns/public/primary?distinctId=${encodeURIComponent(distinctId)}`);
|
|
3057
2967
|
if (res.status === 404) {
|
|
2968
|
+
this.log("Primary campaign not found (404)");
|
|
3058
2969
|
this.cache.setCampaign(key, null, this.cache.nullTTL);
|
|
3059
2970
|
return null;
|
|
3060
2971
|
}
|
|
@@ -3105,7 +3016,7 @@ var _ApiClient = class _ApiClient {
|
|
|
3105
3016
|
headers: { "X-App-Key": this.appKey, "x-distinct-id": distinctId }
|
|
3106
3017
|
});
|
|
3107
3018
|
if (!res.ok) {
|
|
3108
|
-
this.log("
|
|
3019
|
+
this.log("evaluateFlags failed:", res.status, keys);
|
|
3109
3020
|
return {};
|
|
3110
3021
|
}
|
|
3111
3022
|
const raw = res.data;
|
|
@@ -3263,7 +3174,7 @@ var CampaignGateService = class {
|
|
|
3263
3174
|
const isActive = await hasActive();
|
|
3264
3175
|
if (PaywalloClient.getConfig()?.debug) console.info(`[Paywallo] requireSubscription \u2014 hasActive: ${isActive}`);
|
|
3265
3176
|
if (isActive) return true;
|
|
3266
|
-
const r = await this.presentCampaign(apiClient, placement, hasActive, paywallPresenter, campaignPresenter, context);
|
|
3177
|
+
const r = await this.presentCampaign(apiClient, placement, hasActive, paywallPresenter, campaignPresenter, { ...context, forceShow: true });
|
|
3267
3178
|
return r.purchased || r.restored;
|
|
3268
3179
|
}
|
|
3269
3180
|
async preloadCampaign(apiClient, placement, context) {
|
|
@@ -3301,7 +3212,7 @@ var CampaignGateService = class {
|
|
|
3301
3212
|
var campaignGateService = new CampaignGateService();
|
|
3302
3213
|
|
|
3303
3214
|
// src/domains/identity/AdvertisingIdManager.ts
|
|
3304
|
-
var
|
|
3215
|
+
var import_react_native9 = require("react-native");
|
|
3305
3216
|
var ZERO_IDFA = "00000000-0000-0000-0000-000000000000";
|
|
3306
3217
|
var AdvertisingIdManager = class {
|
|
3307
3218
|
constructor() {
|
|
@@ -3312,7 +3223,7 @@ var AdvertisingIdManager = class {
|
|
|
3312
3223
|
const fallback = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
|
|
3313
3224
|
try {
|
|
3314
3225
|
const tracking = await import("expo-tracking-transparency");
|
|
3315
|
-
if (
|
|
3226
|
+
if (import_react_native9.Platform.OS === "ios") {
|
|
3316
3227
|
if (!tracking.isAvailable()) {
|
|
3317
3228
|
const idfv2 = await this.collectIdfv();
|
|
3318
3229
|
this.cached = { ...fallback, idfv: idfv2 };
|
|
@@ -3331,7 +3242,7 @@ var AdvertisingIdManager = class {
|
|
|
3331
3242
|
this.cached = { idfv, idfa, gaid: null, attStatus: status };
|
|
3332
3243
|
return this.cached;
|
|
3333
3244
|
}
|
|
3334
|
-
if (
|
|
3245
|
+
if (import_react_native9.Platform.OS === "android") {
|
|
3335
3246
|
const androidStatus = await tracking.getTrackingPermissionsAsync();
|
|
3336
3247
|
const optedIn = androidStatus.granted;
|
|
3337
3248
|
const rawGaid = optedIn ? tracking.getAdvertisingId() : null;
|
|
@@ -3367,9 +3278,9 @@ var import_async_storage3 = __toESM(require("@react-native-async-storage/async-s
|
|
|
3367
3278
|
var import_react_native_device_info2 = __toESM(require("react-native-device-info"));
|
|
3368
3279
|
|
|
3369
3280
|
// src/domains/identity/MetaBridge.ts
|
|
3370
|
-
var
|
|
3281
|
+
var import_react_native10 = require("react-native");
|
|
3371
3282
|
var TIMEOUT_MS = 2e3;
|
|
3372
|
-
var NativeBridge =
|
|
3283
|
+
var NativeBridge = import_react_native10.NativeModules.PaywalloFBBridge ?? null;
|
|
3373
3284
|
var MetaBridge = class {
|
|
3374
3285
|
async getAnonymousID() {
|
|
3375
3286
|
if (!NativeBridge) return null;
|
|
@@ -3417,11 +3328,11 @@ var MetaBridge = class {
|
|
|
3417
3328
|
var metaBridge = new MetaBridge();
|
|
3418
3329
|
|
|
3419
3330
|
// src/domains/identity/InstallReferrerManager.ts
|
|
3420
|
-
var
|
|
3331
|
+
var import_react_native11 = require("react-native");
|
|
3421
3332
|
var REFERRER_TIMEOUT_MS = 5e3;
|
|
3422
3333
|
var InstallReferrerManager = class {
|
|
3423
3334
|
async getReferrer() {
|
|
3424
|
-
if (
|
|
3335
|
+
if (import_react_native11.Platform.OS !== "android") {
|
|
3425
3336
|
return this.emptyResult();
|
|
3426
3337
|
}
|
|
3427
3338
|
let timerId;
|
|
@@ -3484,14 +3395,77 @@ var installReferrerManager = new InstallReferrerManager();
|
|
|
3484
3395
|
var import_react_native13 = require("react-native");
|
|
3485
3396
|
init_uuid();
|
|
3486
3397
|
|
|
3398
|
+
// src/utils/deviceInfo.ts
|
|
3399
|
+
var import_react_native12 = require("react-native");
|
|
3400
|
+
async function getAppVersion() {
|
|
3401
|
+
try {
|
|
3402
|
+
const app = await import("expo-application");
|
|
3403
|
+
if (app.nativeApplicationVersion) {
|
|
3404
|
+
return app.nativeApplicationVersion;
|
|
3405
|
+
}
|
|
3406
|
+
} catch {
|
|
3407
|
+
}
|
|
3408
|
+
try {
|
|
3409
|
+
const DeviceInfo2 = (await import("react-native-device-info")).default;
|
|
3410
|
+
const v = DeviceInfo2.getVersion();
|
|
3411
|
+
if (v) return v;
|
|
3412
|
+
} catch {
|
|
3413
|
+
}
|
|
3414
|
+
return "unknown";
|
|
3415
|
+
}
|
|
3416
|
+
async function getDeviceModel() {
|
|
3417
|
+
try {
|
|
3418
|
+
const DeviceInfo2 = (await import("react-native-device-info")).default;
|
|
3419
|
+
const model = DeviceInfo2.getModel();
|
|
3420
|
+
if (model) return model;
|
|
3421
|
+
} catch {
|
|
3422
|
+
}
|
|
3423
|
+
return "unknown";
|
|
3424
|
+
}
|
|
3425
|
+
function getOsVersion() {
|
|
3426
|
+
const v = import_react_native12.Platform.Version;
|
|
3427
|
+
if (typeof v === "number") return String(v);
|
|
3428
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
3429
|
+
return "unknown";
|
|
3430
|
+
}
|
|
3431
|
+
async function collectDeviceInfo() {
|
|
3432
|
+
const [appVersion, deviceModel] = await Promise.all([
|
|
3433
|
+
getAppVersion(),
|
|
3434
|
+
getDeviceModel()
|
|
3435
|
+
]);
|
|
3436
|
+
return {
|
|
3437
|
+
appVersion,
|
|
3438
|
+
deviceModel,
|
|
3439
|
+
osVersion: getOsVersion()
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3487
3443
|
// src/domains/session/sessionTracking.ts
|
|
3488
3444
|
async function trackSessionStart(apiClient, sessionId, sessionStartedAt) {
|
|
3489
3445
|
const distinctId = identityManager.getDistinctId();
|
|
3490
|
-
await
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
});
|
|
3446
|
+
const deviceInfo = await collectDeviceInfo().catch(() => ({
|
|
3447
|
+
appVersion: "unknown",
|
|
3448
|
+
deviceModel: "unknown",
|
|
3449
|
+
osVersion: "unknown"
|
|
3450
|
+
}));
|
|
3451
|
+
await Promise.all([
|
|
3452
|
+
apiClient.startSession(
|
|
3453
|
+
distinctId,
|
|
3454
|
+
sessionId,
|
|
3455
|
+
void 0,
|
|
3456
|
+
deviceInfo.appVersion,
|
|
3457
|
+
deviceInfo.deviceModel,
|
|
3458
|
+
deviceInfo.osVersion
|
|
3459
|
+
),
|
|
3460
|
+
apiClient.trackEvent("$session_start", distinctId, {
|
|
3461
|
+
sessionId,
|
|
3462
|
+
timestamp: sessionStartedAt?.toISOString() ?? null,
|
|
3463
|
+
appVersion: deviceInfo.appVersion,
|
|
3464
|
+
deviceModel: deviceInfo.deviceModel,
|
|
3465
|
+
osVersion: deviceInfo.osVersion
|
|
3466
|
+
}).catch(() => {
|
|
3467
|
+
})
|
|
3468
|
+
]);
|
|
3495
3469
|
}
|
|
3496
3470
|
async function trackSessionEnd(apiClient, sessionId, durationSeconds, sessionStartedAt) {
|
|
3497
3471
|
const distinctId = identityManager.getDistinctId();
|
|
@@ -3588,6 +3562,9 @@ var SessionManager = class {
|
|
|
3588
3562
|
if (!this.sessionId || !this.sessionStartedAt) {
|
|
3589
3563
|
return;
|
|
3590
3564
|
}
|
|
3565
|
+
if (this.apiClient) {
|
|
3566
|
+
await this.apiClient.flushEventBatch();
|
|
3567
|
+
}
|
|
3591
3568
|
await this.trackSessionEnd();
|
|
3592
3569
|
this.sessionId = null;
|
|
3593
3570
|
this.sessionStartedAt = null;
|
|
@@ -3672,6 +3649,9 @@ var SessionManager = class {
|
|
|
3672
3649
|
async handleBackground() {
|
|
3673
3650
|
this.backgroundTimestamp = Date.now();
|
|
3674
3651
|
await this.trackAppBackground();
|
|
3652
|
+
if (this.apiClient) {
|
|
3653
|
+
await this.apiClient.flushEventBatch();
|
|
3654
|
+
}
|
|
3675
3655
|
}
|
|
3676
3656
|
async checkEmergencyPaywall() {
|
|
3677
3657
|
if (!this.apiClient || !this.emergencyPaywallHandler) {
|
|
@@ -4027,7 +4007,6 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4027
4007
|
]);
|
|
4028
4008
|
this.apiClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
4029
4009
|
queueProcessor.initialize(this.apiClient.getHttpClient(), { debug: config.debug });
|
|
4030
|
-
affiliateManager.initialize(this.apiClient, config.debug);
|
|
4031
4010
|
subscriptionManager.init({
|
|
4032
4011
|
serverUrl: this.apiClient.getBaseUrl(),
|
|
4033
4012
|
appKey: config.appKey,
|
|
@@ -4054,6 +4033,12 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4054
4033
|
this.resolveReady = null;
|
|
4055
4034
|
}
|
|
4056
4035
|
if (config.debug) console.info("[Paywallo INIT] complete");
|
|
4036
|
+
if (distinctId) {
|
|
4037
|
+
this.apiClient.getSubscriptionStatus(distinctId).then(() => {
|
|
4038
|
+
if (config.debug) console.info("[Paywallo SUB] preloaded on boot");
|
|
4039
|
+
}).catch(() => {
|
|
4040
|
+
});
|
|
4041
|
+
}
|
|
4057
4042
|
if (this.apiClient) {
|
|
4058
4043
|
const apiClientRef = this.apiClient;
|
|
4059
4044
|
if (config.autoPreloadCampaign) {
|
|
@@ -4079,18 +4064,21 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4079
4064
|
}
|
|
4080
4065
|
async identify(options) {
|
|
4081
4066
|
this.ensureInitialized();
|
|
4067
|
+
if (this.config?.debug) console.info("[Paywallo IDENTIFY]", options);
|
|
4082
4068
|
await identityManager.identify(options);
|
|
4083
4069
|
}
|
|
4084
4070
|
async track(eventName, options) {
|
|
4085
4071
|
const apiClient = this.getApiClientOrThrow();
|
|
4086
4072
|
const distinctId = identityManager.getDistinctId();
|
|
4087
4073
|
if (!distinctId) {
|
|
4074
|
+
if (this.config?.debug) console.info(`[Paywallo TRACK] ${eventName} skipped (no distinctId)`);
|
|
4088
4075
|
return;
|
|
4089
4076
|
}
|
|
4090
4077
|
if (!isValidEventName(eventName)) {
|
|
4091
4078
|
const msg = `Invalid event name: "${eventName}". Use snake_case or $reserved_name.`;
|
|
4092
4079
|
throw new ClientError(CLIENT_ERROR_CODES.INVALID_EVENT_NAME, msg);
|
|
4093
4080
|
}
|
|
4081
|
+
if (this.config?.debug && eventName.startsWith("$purchase")) console.info(`[Paywallo TRACK] ${eventName}`, options?.properties ?? {});
|
|
4094
4082
|
const sessionId = sessionManager.getSessionId();
|
|
4095
4083
|
await apiClient.trackEvent(eventName, distinctId, {
|
|
4096
4084
|
...identityManager.getProperties(),
|
|
@@ -4111,14 +4099,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4111
4099
|
const now = Date.now();
|
|
4112
4100
|
const timeOnPreviousStep = this.lastOnboardingStepTimestamp !== null ? Math.round((now - this.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
4113
4101
|
this.lastOnboardingStepTimestamp = now;
|
|
4114
|
-
const sessionId = sessionManager.getSessionId();
|
|
4115
4102
|
await apiClient.trackEvent("$onboarding_step", distinctId, {
|
|
4116
|
-
...identityManager.getProperties(),
|
|
4117
4103
|
stepIndex: index,
|
|
4118
4104
|
stepName: name,
|
|
4119
|
-
|
|
4120
|
-
timeOnPreviousStep,
|
|
4121
|
-
...sessionId && { sessionId }
|
|
4105
|
+
timeOnPreviousStep
|
|
4122
4106
|
});
|
|
4123
4107
|
}
|
|
4124
4108
|
async coreAction(actionName) {
|
|
@@ -4153,10 +4137,14 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4153
4137
|
try {
|
|
4154
4138
|
const distinctId = identityManager.getDistinctId();
|
|
4155
4139
|
if (!distinctId) {
|
|
4140
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192 null (no distinctId)`);
|
|
4156
4141
|
return { variant: null };
|
|
4157
4142
|
}
|
|
4158
|
-
|
|
4143
|
+
const result = await this.getApiClientOrThrow().getVariant(flagKey, distinctId);
|
|
4144
|
+
if (this.config?.debug) console.info(`[Paywallo FLAG] ${flagKey} \u2192`, result.variant);
|
|
4145
|
+
return result;
|
|
4159
4146
|
} catch (error) {
|
|
4147
|
+
if (this.config?.debug) console.warn(`[Paywallo FLAG] ${flagKey} \u2192 error`, error);
|
|
4160
4148
|
if (this.apiClient) void this.apiClient.reportError("GET_VARIANT_FAILED", error instanceof Error ? error.message : String(error));
|
|
4161
4149
|
return { variant: null };
|
|
4162
4150
|
}
|
|
@@ -4189,21 +4177,34 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4189
4177
|
}
|
|
4190
4178
|
async presentCampaign(placement, context) {
|
|
4191
4179
|
this.ensureInitialized();
|
|
4192
|
-
|
|
4180
|
+
if (this.config?.debug) console.info(`[Paywallo CAMPAIGN] presenting ${placement}`);
|
|
4181
|
+
const result = await campaignGateService.presentCampaign(this.getApiClientOrThrow(), placement, () => this.hasActiveSubscription(), this.paywallPresenter, this.campaignPresenter, context);
|
|
4182
|
+
if (this.config?.debug) {
|
|
4183
|
+
if (result.error) console.warn(`[Paywallo CAMPAIGN] ${placement} error:`, result.error.message);
|
|
4184
|
+
else console.info(`[Paywallo CAMPAIGN] ${placement} result:`, { purchased: result.purchased, cancelled: result.cancelled, restored: result.restored, skippedReason: result.skippedReason });
|
|
4185
|
+
}
|
|
4186
|
+
return result;
|
|
4193
4187
|
}
|
|
4194
4188
|
async hasActiveSubscription() {
|
|
4195
4189
|
this.ensureInitialized();
|
|
4196
4190
|
try {
|
|
4197
4191
|
if (this.activeChecker) {
|
|
4198
|
-
|
|
4192
|
+
const result = await this.activeChecker();
|
|
4193
|
+
const isActive2 = result === true;
|
|
4194
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (checker):", isActive2);
|
|
4195
|
+
return isActive2;
|
|
4199
4196
|
}
|
|
4200
4197
|
const distinctId = identityManager.getDistinctId();
|
|
4201
4198
|
if (!distinctId || !this.apiClient) {
|
|
4199
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription: false (no distinctId/apiClient)");
|
|
4202
4200
|
return false;
|
|
4203
4201
|
}
|
|
4204
4202
|
const status = await this.apiClient.getSubscriptionStatus(distinctId);
|
|
4205
|
-
|
|
4203
|
+
const isActive = status.hasActiveSubscription === true;
|
|
4204
|
+
if (this.config?.debug) console.info("[Paywallo SUB] hasActiveSubscription (server):", isActive);
|
|
4205
|
+
return isActive;
|
|
4206
4206
|
} catch (error) {
|
|
4207
|
+
if (this.config?.debug) console.warn("[Paywallo SUB] hasActiveSubscription error", error);
|
|
4207
4208
|
if (this.apiClient) void this.apiClient.reportError("SUBSCRIPTION_CHECK_FAILED", error instanceof Error ? error.message : "hasActiveSubscription failed");
|
|
4208
4209
|
return false;
|
|
4209
4210
|
}
|
|
@@ -4224,7 +4225,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4224
4225
|
async restorePurchases() {
|
|
4225
4226
|
this.ensureInitialized();
|
|
4226
4227
|
if (!this.restoreHandler) throw new PaywallError(PAYWALL_ERROR_CODES.NOT_INITIALIZED, "PaywalloProvider not mounted. Wrap your app with <PaywalloProvider>");
|
|
4227
|
-
|
|
4228
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] starting");
|
|
4229
|
+
const result = await this.restoreHandler();
|
|
4230
|
+
if (this.config?.debug) console.info("[Paywallo RESTORE] result:", { success: result.success, restoredProducts: result.restoredProducts?.length ?? 0 });
|
|
4231
|
+
return result;
|
|
4228
4232
|
}
|
|
4229
4233
|
async reset() {
|
|
4230
4234
|
await identityManager.reset();
|
|
@@ -4319,6 +4323,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4319
4323
|
registerEmergencyPaywallHandler(h) {
|
|
4320
4324
|
sessionManager.registerEmergencyPaywallHandler(h);
|
|
4321
4325
|
}
|
|
4326
|
+
async getEmergencyPaywall() {
|
|
4327
|
+
if (!this.apiClient) throw new ClientError(CLIENT_ERROR_CODES.NOT_INITIALIZED, "SDK not initialized");
|
|
4328
|
+
return this.apiClient.getEmergencyPaywall();
|
|
4329
|
+
}
|
|
4322
4330
|
async requireSubscription(paywallPlacement) {
|
|
4323
4331
|
this.ensureInitialized();
|
|
4324
4332
|
if (await this.hasActiveSubscription()) return true;
|
|
@@ -4863,7 +4871,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4863
4871
|
// src/hooks/useSubscriptionSync.ts
|
|
4864
4872
|
var import_react17 = require("react");
|
|
4865
4873
|
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
4866
|
-
var ACTIVE_STATUSES = ["active", "
|
|
4874
|
+
var ACTIVE_STATUSES = ["active", "in_grace_period"];
|
|
4867
4875
|
function toDomainSubscriptionInfo(sub) {
|
|
4868
4876
|
return {
|
|
4869
4877
|
id: "",
|
|
@@ -4882,7 +4890,7 @@ function toDomainResponse(status) {
|
|
|
4882
4890
|
return {
|
|
4883
4891
|
hasActiveSubscription: status.hasActiveSubscription,
|
|
4884
4892
|
subscription: status.subscription ? toDomainSubscriptionInfo(status.subscription) : null,
|
|
4885
|
-
entitlements: []
|
|
4893
|
+
entitlements: status.entitlements ?? []
|
|
4886
4894
|
};
|
|
4887
4895
|
}
|
|
4888
4896
|
function isSubscriptionStillActive(sub) {
|
|
@@ -4938,13 +4946,14 @@ function useSubscriptionSync() {
|
|
|
4938
4946
|
const persisted = await subscriptionCache.get(distinctId);
|
|
4939
4947
|
if (persisted && !persisted.isStale) {
|
|
4940
4948
|
const persistedSub = persisted.data.subscription;
|
|
4949
|
+
const persistedStatus = persistedSub?.status;
|
|
4941
4950
|
const sub = persistedSub ? {
|
|
4942
4951
|
productId: persistedSub.productId,
|
|
4943
|
-
status:
|
|
4952
|
+
status: persistedStatus,
|
|
4944
4953
|
expiresAt: persistedSub.expiresAt ?? null,
|
|
4945
4954
|
platform: persistedSub.platform,
|
|
4946
4955
|
autoRenewEnabled: persistedSub.willRenew,
|
|
4947
|
-
inGracePeriod:
|
|
4956
|
+
inGracePeriod: persistedStatus === "in_grace_period"
|
|
4948
4957
|
} : null;
|
|
4949
4958
|
const stillActive = isSubscriptionStillActive(sub);
|
|
4950
4959
|
if (stillActive) {
|
|
@@ -4964,7 +4973,7 @@ function useSubscriptionSync() {
|
|
|
4964
4973
|
cacheRef.current = { data: sub, expiresAt: Date.now() + CACHE_TTL_MS2 };
|
|
4965
4974
|
setSubscription(sub);
|
|
4966
4975
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
4967
|
-
return status.hasActiveSubscription;
|
|
4976
|
+
return status.hasActiveSubscription === true;
|
|
4968
4977
|
} catch {
|
|
4969
4978
|
return await resolveOfflineFromCache(distinctId);
|
|
4970
4979
|
}
|
|
@@ -4982,14 +4991,14 @@ function useSubscriptionSync() {
|
|
|
4982
4991
|
const persisted = await subscriptionCache.get(distinctId);
|
|
4983
4992
|
if (!persisted?.data.subscription) return null;
|
|
4984
4993
|
const s = persisted.data.subscription;
|
|
4985
|
-
const
|
|
4994
|
+
const status = s.status;
|
|
4986
4995
|
return {
|
|
4987
4996
|
productId: s.productId,
|
|
4988
|
-
status
|
|
4997
|
+
status,
|
|
4989
4998
|
expiresAt: s.expiresAt ?? null,
|
|
4990
4999
|
platform: s.platform,
|
|
4991
5000
|
autoRenewEnabled: s.willRenew,
|
|
4992
|
-
inGracePeriod:
|
|
5001
|
+
inGracePeriod: status === "in_grace_period"
|
|
4993
5002
|
};
|
|
4994
5003
|
} catch {
|
|
4995
5004
|
return null;
|
|
@@ -5415,10 +5424,7 @@ var Paywallo = PaywalloClient;
|
|
|
5415
5424
|
var index_default = Paywallo;
|
|
5416
5425
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5417
5426
|
0 && (module.exports = {
|
|
5418
|
-
AFFILIATE_ERROR_CODES,
|
|
5419
5427
|
ANALYTICS_ERROR_CODES,
|
|
5420
|
-
AffiliateError,
|
|
5421
|
-
AffiliateManager,
|
|
5422
5428
|
AnalyticsError,
|
|
5423
5429
|
ApiClient,
|
|
5424
5430
|
CAMPAIGN_ERROR_CODES,
|
|
@@ -5436,7 +5442,6 @@ var index_default = Paywallo;
|
|
|
5436
5442
|
PaywallError,
|
|
5437
5443
|
PaywallModal,
|
|
5438
5444
|
Paywallo,
|
|
5439
|
-
PaywalloAffiliate,
|
|
5440
5445
|
PaywalloClient,
|
|
5441
5446
|
PaywalloContext,
|
|
5442
5447
|
PaywalloError,
|
|
@@ -5446,7 +5451,6 @@ var index_default = Paywallo;
|
|
|
5446
5451
|
SessionError,
|
|
5447
5452
|
SessionManager,
|
|
5448
5453
|
SubscriptionCache,
|
|
5449
|
-
affiliateManager,
|
|
5450
5454
|
createPurchaseError,
|
|
5451
5455
|
detectDeviceLanguage,
|
|
5452
5456
|
getCurrentLanguage,
|