@virex-tech/paywallo-sdk 1.4.1 → 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 +247 -273
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +243 -264
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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 };
|
|
@@ -1572,227 +1575,6 @@ function usePaywallPresenter(preloadedWebView, setPreloadedWebView) {
|
|
|
1572
1575
|
return { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady, handlePreloadedClose, setShowingPreloadedWebView, presentedAtRef };
|
|
1573
1576
|
}
|
|
1574
1577
|
|
|
1575
|
-
// src/domains/affiliate/AffiliateError.ts
|
|
1576
|
-
var AffiliateError = class extends PaywalloError {
|
|
1577
|
-
constructor(code, message) {
|
|
1578
|
-
super("affiliate", code, message);
|
|
1579
|
-
this.name = "AffiliateError";
|
|
1580
|
-
}
|
|
1581
|
-
};
|
|
1582
|
-
var AFFILIATE_ERROR_CODES = {
|
|
1583
|
-
NOT_INITIALIZED: "AFFILIATE_NOT_INITIALIZED",
|
|
1584
|
-
COUPON_REGISTER_FAILED: "AFFILIATE_COUPON_REGISTER_FAILED",
|
|
1585
|
-
COUPON_APPLY_FAILED: "AFFILIATE_COUPON_APPLY_FAILED",
|
|
1586
|
-
BALANCE_FETCH_FAILED: "AFFILIATE_BALANCE_FETCH_FAILED",
|
|
1587
|
-
WITHDRAWAL_FAILED: "AFFILIATE_WITHDRAWAL_FAILED",
|
|
1588
|
-
NETWORK_ERROR: "AFFILIATE_NETWORK_ERROR"
|
|
1589
|
-
};
|
|
1590
|
-
|
|
1591
|
-
// src/domains/affiliate/affiliateHttp.ts
|
|
1592
|
-
function buildQueryString(params) {
|
|
1593
|
-
if (!params) return "";
|
|
1594
|
-
const entries = Object.entries(params).filter(([, v]) => v !== void 0 && v !== null);
|
|
1595
|
-
if (entries.length === 0) return "";
|
|
1596
|
-
return `?${entries.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`).join("&")}`;
|
|
1597
|
-
}
|
|
1598
|
-
async function affiliateGet(apiClient, path, params) {
|
|
1599
|
-
const response = await apiClient.get(`${path}${buildQueryString(params)}`);
|
|
1600
|
-
return response.data;
|
|
1601
|
-
}
|
|
1602
|
-
async function affiliatePost(apiClient, path, body) {
|
|
1603
|
-
const response = await apiClient.post(path, body);
|
|
1604
|
-
return response.data;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
// src/domains/affiliate/affiliateDateMappers.ts
|
|
1608
|
-
function mapRawCoupon(raw) {
|
|
1609
|
-
return { code: raw.code, status: raw.status, createdAt: new Date(raw.createdAt) };
|
|
1610
|
-
}
|
|
1611
|
-
function mapRawCommission(raw) {
|
|
1612
|
-
return { ...raw, createdAt: new Date(raw.createdAt) };
|
|
1613
|
-
}
|
|
1614
|
-
function mapRawWithdrawal(raw) {
|
|
1615
|
-
return { ...raw, createdAt: new Date(raw.createdAt) };
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
// src/domains/affiliate/AffiliateManager.ts
|
|
1619
|
-
var AffiliateManager = class {
|
|
1620
|
-
constructor() {
|
|
1621
|
-
this.apiClient = null;
|
|
1622
|
-
this.debug = false;
|
|
1623
|
-
}
|
|
1624
|
-
initialize(apiClient, debug = false) {
|
|
1625
|
-
this.apiClient = apiClient;
|
|
1626
|
-
this.debug = debug;
|
|
1627
|
-
this.log("AffiliateManager initialized");
|
|
1628
|
-
}
|
|
1629
|
-
async registerCoupon(code) {
|
|
1630
|
-
this.ensureInitialized();
|
|
1631
|
-
const distinctId = identityManager.getDistinctId();
|
|
1632
|
-
try {
|
|
1633
|
-
const response = await this.post("/api/v1/affiliate/register-coupon", {
|
|
1634
|
-
code,
|
|
1635
|
-
distinctId
|
|
1636
|
-
});
|
|
1637
|
-
if (response.success && response.coupon) {
|
|
1638
|
-
this.log("Coupon registered:", code);
|
|
1639
|
-
return { success: true, coupon: mapRawCoupon(response.coupon) };
|
|
1640
|
-
}
|
|
1641
|
-
return {
|
|
1642
|
-
success: false,
|
|
1643
|
-
error: response.error
|
|
1644
|
-
};
|
|
1645
|
-
} catch (error) {
|
|
1646
|
-
this.log("Failed to register coupon:", error);
|
|
1647
|
-
return {
|
|
1648
|
-
success: false,
|
|
1649
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1650
|
-
};
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
async applyCoupon(code) {
|
|
1654
|
-
this.ensureInitialized();
|
|
1655
|
-
const distinctId = identityManager.getDistinctId();
|
|
1656
|
-
try {
|
|
1657
|
-
const response = await this.post("/api/v1/affiliate/apply-coupon", {
|
|
1658
|
-
code,
|
|
1659
|
-
distinctId
|
|
1660
|
-
});
|
|
1661
|
-
if (response.success) {
|
|
1662
|
-
this.log("Coupon applied:", code);
|
|
1663
|
-
}
|
|
1664
|
-
return response;
|
|
1665
|
-
} catch (error) {
|
|
1666
|
-
this.log("Failed to apply coupon:", error);
|
|
1667
|
-
return {
|
|
1668
|
-
success: false,
|
|
1669
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
async getMyCoupon() {
|
|
1674
|
-
this.ensureInitialized();
|
|
1675
|
-
const distinctId = identityManager.getDistinctId();
|
|
1676
|
-
try {
|
|
1677
|
-
const response = await this.get("/api/v1/affiliate/my-coupon", { distinctId });
|
|
1678
|
-
if (response.coupon) {
|
|
1679
|
-
return { coupon: mapRawCoupon(response.coupon) };
|
|
1680
|
-
}
|
|
1681
|
-
return { coupon: null };
|
|
1682
|
-
} catch (error) {
|
|
1683
|
-
this.log("Failed to get my coupon:", error);
|
|
1684
|
-
return { coupon: null };
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
async getAppliedCoupon() {
|
|
1688
|
-
this.ensureInitialized();
|
|
1689
|
-
const distinctId = identityManager.getDistinctId();
|
|
1690
|
-
try {
|
|
1691
|
-
const response = await this.get("/api/v1/affiliate/applied-coupon", { distinctId });
|
|
1692
|
-
return response;
|
|
1693
|
-
} catch (error) {
|
|
1694
|
-
this.log("Failed to get applied coupon:", error);
|
|
1695
|
-
return { coupon: null };
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
async getBalance() {
|
|
1699
|
-
this.ensureInitialized();
|
|
1700
|
-
const distinctId = identityManager.getDistinctId();
|
|
1701
|
-
try {
|
|
1702
|
-
const response = await this.get("/api/v1/affiliate/balance", {
|
|
1703
|
-
distinctId
|
|
1704
|
-
});
|
|
1705
|
-
return response;
|
|
1706
|
-
} catch (error) {
|
|
1707
|
-
this.log("Failed to get balance:", error);
|
|
1708
|
-
return {
|
|
1709
|
-
total: 0,
|
|
1710
|
-
pending: 0,
|
|
1711
|
-
available: 0,
|
|
1712
|
-
withdrawn: 0
|
|
1713
|
-
};
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
async getCommissions() {
|
|
1717
|
-
this.ensureInitialized();
|
|
1718
|
-
const distinctId = identityManager.getDistinctId();
|
|
1719
|
-
try {
|
|
1720
|
-
const response = await this.get("/api/v1/affiliate/commissions", { distinctId });
|
|
1721
|
-
return response.commissions.map(mapRawCommission);
|
|
1722
|
-
} catch (error) {
|
|
1723
|
-
this.log("Failed to get commissions:", error);
|
|
1724
|
-
return [];
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
async requestWithdrawal(amount) {
|
|
1728
|
-
this.ensureInitialized();
|
|
1729
|
-
const distinctId = identityManager.getDistinctId();
|
|
1730
|
-
try {
|
|
1731
|
-
const response = await this.post("/api/v1/affiliate/withdraw", {
|
|
1732
|
-
amount,
|
|
1733
|
-
distinctId
|
|
1734
|
-
});
|
|
1735
|
-
if (response.success && response.withdrawal) {
|
|
1736
|
-
this.log("Withdrawal requested:", amount);
|
|
1737
|
-
return { success: true, withdrawal: mapRawWithdrawal(response.withdrawal) };
|
|
1738
|
-
}
|
|
1739
|
-
return {
|
|
1740
|
-
success: false,
|
|
1741
|
-
error: response.error
|
|
1742
|
-
};
|
|
1743
|
-
} catch (error) {
|
|
1744
|
-
this.log("Failed to request withdrawal:", error);
|
|
1745
|
-
return {
|
|
1746
|
-
success: false,
|
|
1747
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1748
|
-
};
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
async getWithdrawals() {
|
|
1752
|
-
this.ensureInitialized();
|
|
1753
|
-
const distinctId = identityManager.getDistinctId();
|
|
1754
|
-
try {
|
|
1755
|
-
const response = await this.get("/api/v1/affiliate/withdrawals", { distinctId });
|
|
1756
|
-
return response.withdrawals.map(mapRawWithdrawal);
|
|
1757
|
-
} catch (error) {
|
|
1758
|
-
this.log("Failed to get withdrawals:", error);
|
|
1759
|
-
return [];
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
async get(path, params) {
|
|
1763
|
-
this.ensureInitialized();
|
|
1764
|
-
return affiliateGet(this.apiClient, path, params);
|
|
1765
|
-
}
|
|
1766
|
-
async post(path, body) {
|
|
1767
|
-
this.ensureInitialized();
|
|
1768
|
-
return affiliatePost(this.apiClient, path, body);
|
|
1769
|
-
}
|
|
1770
|
-
ensureInitialized() {
|
|
1771
|
-
if (!this.apiClient) {
|
|
1772
|
-
throw new AffiliateError(
|
|
1773
|
-
AFFILIATE_ERROR_CODES.NOT_INITIALIZED,
|
|
1774
|
-
"AffiliateManager not initialized. Call initialize() first"
|
|
1775
|
-
);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
log(...args) {
|
|
1779
|
-
if (this.debug) console.log("[Paywallo:Affiliate]", ...args);
|
|
1780
|
-
}
|
|
1781
|
-
};
|
|
1782
|
-
var affiliateManager = new AffiliateManager();
|
|
1783
|
-
|
|
1784
|
-
// src/domains/affiliate/PaywalloAffiliate.ts
|
|
1785
|
-
var PaywalloAffiliate = {
|
|
1786
|
-
registerCoupon: (code) => affiliateManager.registerCoupon(code),
|
|
1787
|
-
applyCoupon: (code) => affiliateManager.applyCoupon(code),
|
|
1788
|
-
getMyCoupon: () => affiliateManager.getMyCoupon(),
|
|
1789
|
-
getAppliedCoupon: () => affiliateManager.getAppliedCoupon(),
|
|
1790
|
-
getBalance: () => affiliateManager.getBalance(),
|
|
1791
|
-
getCommissions: () => affiliateManager.getCommissions(),
|
|
1792
|
-
requestWithdrawal: (amount) => affiliateManager.requestWithdrawal(amount),
|
|
1793
|
-
getWithdrawals: () => affiliateManager.getWithdrawals()
|
|
1794
|
-
};
|
|
1795
|
-
|
|
1796
1578
|
// src/domains/subscription/SubscriptionCache.ts
|
|
1797
1579
|
var LEGACY_CACHE_KEY = "subscription_cache";
|
|
1798
1580
|
var CACHE_KEY_PREFIX = "subscription_cache:";
|
|
@@ -1902,9 +1684,6 @@ var SubscriptionCache = class {
|
|
|
1902
1684
|
};
|
|
1903
1685
|
var subscriptionCache = new SubscriptionCache();
|
|
1904
1686
|
|
|
1905
|
-
// src/domains/subscription/SubscriptionManager.ts
|
|
1906
|
-
var import_react_native7 = require("react-native");
|
|
1907
|
-
|
|
1908
1687
|
// src/domains/session/SessionError.ts
|
|
1909
1688
|
var SessionError = class extends PaywalloError {
|
|
1910
1689
|
constructor(code, message) {
|
|
@@ -1992,11 +1771,10 @@ var SubscriptionManagerClass = class {
|
|
|
1992
1771
|
if (!this.config) {
|
|
1993
1772
|
return this.getEmptyStatus();
|
|
1994
1773
|
}
|
|
1995
|
-
const url = new URL(`${this.config.serverUrl}/
|
|
1774
|
+
const url = new URL(`${this.config.serverUrl}/purchases/status/${encodeURIComponent(this.config.appKey)}`);
|
|
1996
1775
|
if (this.userId) {
|
|
1997
|
-
url.searchParams.set("
|
|
1776
|
+
url.searchParams.set("distinctId", this.userId);
|
|
1998
1777
|
}
|
|
1999
|
-
url.searchParams.set("platform", import_react_native7.Platform.OS);
|
|
2000
1778
|
const response = await fetch(url.toString(), {
|
|
2001
1779
|
method: "GET",
|
|
2002
1780
|
headers: {
|
|
@@ -2051,7 +1829,7 @@ var SubscriptionManagerClass = class {
|
|
|
2051
1829
|
var subscriptionManager = new SubscriptionManagerClass();
|
|
2052
1830
|
|
|
2053
1831
|
// src/core/ApiClient.ts
|
|
2054
|
-
var
|
|
1832
|
+
var import_react_native8 = require("react-native");
|
|
2055
1833
|
|
|
2056
1834
|
// src/core/apiUrlUtils.ts
|
|
2057
1835
|
var DEFAULT_WEB_URL = "https://paywallo.com.br";
|
|
@@ -2301,7 +2079,7 @@ var HttpClient = class {
|
|
|
2301
2079
|
};
|
|
2302
2080
|
|
|
2303
2081
|
// src/core/network/NetworkMonitor.ts
|
|
2304
|
-
var
|
|
2082
|
+
var import_react_native7 = require("react-native");
|
|
2305
2083
|
|
|
2306
2084
|
// src/core/network/types.ts
|
|
2307
2085
|
var DEFAULT_NETWORK_CONFIG = {
|
|
@@ -2338,7 +2116,7 @@ var NetworkMonitorClass = class {
|
|
|
2338
2116
|
}, this.config.checkInterval);
|
|
2339
2117
|
}
|
|
2340
2118
|
setupAppStateListener() {
|
|
2341
|
-
this.appStateSubscription =
|
|
2119
|
+
this.appStateSubscription = import_react_native7.AppState.addEventListener("change", (state) => {
|
|
2342
2120
|
if (state === "active") {
|
|
2343
2121
|
void this.checkConnectivity();
|
|
2344
2122
|
}
|
|
@@ -2734,9 +2512,78 @@ var QueueProcessorClass = class {
|
|
|
2734
2512
|
this.log("Offline, skipping queue processing");
|
|
2735
2513
|
return { processed: 0, failed: 0 };
|
|
2736
2514
|
}
|
|
2737
|
-
|
|
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
|
+
}
|
|
2738
2529
|
return this.processItem(item);
|
|
2739
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 };
|
|
2740
2587
|
}
|
|
2741
2588
|
async processItem(item) {
|
|
2742
2589
|
if (!this.httpClient) {
|
|
@@ -2887,10 +2734,14 @@ var ApiCache = class {
|
|
|
2887
2734
|
};
|
|
2888
2735
|
|
|
2889
2736
|
// src/core/ApiClient.ts
|
|
2890
|
-
var SDK_VERSION = "1.
|
|
2737
|
+
var SDK_VERSION = "1.5.0";
|
|
2891
2738
|
var _ApiClient = class _ApiClient {
|
|
2892
2739
|
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
2893
2740
|
this.cache = new ApiCache();
|
|
2741
|
+
this.eventBatch = [];
|
|
2742
|
+
this.batchTimer = null;
|
|
2743
|
+
this.BATCH_MAX_SIZE = 10;
|
|
2744
|
+
this.BATCH_FLUSH_MS = 5e3;
|
|
2894
2745
|
this.appKey = appKey;
|
|
2895
2746
|
this.baseUrl = apiUrl;
|
|
2896
2747
|
this.webUrl = deriveWebUrl(this.baseUrl);
|
|
@@ -2943,30 +2794,79 @@ var _ApiClient = class _ApiClient {
|
|
|
2943
2794
|
message,
|
|
2944
2795
|
context,
|
|
2945
2796
|
sdkVersion: SDK_VERSION,
|
|
2946
|
-
platform:
|
|
2797
|
+
platform: import_react_native8.Platform.OS
|
|
2947
2798
|
}, true);
|
|
2948
2799
|
} catch (err) {
|
|
2949
2800
|
if (this.debug) console.warn("[Paywallo:ApiClient] reportError failed", err);
|
|
2950
2801
|
}
|
|
2951
2802
|
}
|
|
2952
2803
|
async trackEvent(eventName, distinctId, properties, timestamp) {
|
|
2953
|
-
|
|
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 = {
|
|
2954
2811
|
eventName,
|
|
2955
2812
|
distinctId,
|
|
2956
|
-
properties: { ...properties, platform:
|
|
2813
|
+
properties: { ...properties, platform: import_react_native8.Platform.OS },
|
|
2957
2814
|
timestamp: timestamp ?? Date.now(),
|
|
2958
2815
|
environment: this.environment.toLowerCase()
|
|
2959
|
-
}
|
|
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
|
+
}
|
|
2960
2857
|
}
|
|
2961
2858
|
async identify(distinctId, properties, email, deviceId) {
|
|
2962
|
-
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");
|
|
2963
2860
|
}
|
|
2964
|
-
async startSession(distinctId, sessionId, platform) {
|
|
2861
|
+
async startSession(distinctId, sessionId, platform, appVersion, deviceModel, osVersion) {
|
|
2965
2862
|
await this.postWithQueue("/api/v1/sessions/start", {
|
|
2966
2863
|
distinctId,
|
|
2967
2864
|
sessionId,
|
|
2968
|
-
platform: platform ??
|
|
2969
|
-
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)
|
|
2970
2870
|
}, `session.start:${sessionId}`);
|
|
2971
2871
|
return { success: true };
|
|
2972
2872
|
}
|
|
@@ -3274,7 +3174,7 @@ var CampaignGateService = class {
|
|
|
3274
3174
|
const isActive = await hasActive();
|
|
3275
3175
|
if (PaywalloClient.getConfig()?.debug) console.info(`[Paywallo] requireSubscription \u2014 hasActive: ${isActive}`);
|
|
3276
3176
|
if (isActive) return true;
|
|
3277
|
-
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 });
|
|
3278
3178
|
return r.purchased || r.restored;
|
|
3279
3179
|
}
|
|
3280
3180
|
async preloadCampaign(apiClient, placement, context) {
|
|
@@ -3312,7 +3212,7 @@ var CampaignGateService = class {
|
|
|
3312
3212
|
var campaignGateService = new CampaignGateService();
|
|
3313
3213
|
|
|
3314
3214
|
// src/domains/identity/AdvertisingIdManager.ts
|
|
3315
|
-
var
|
|
3215
|
+
var import_react_native9 = require("react-native");
|
|
3316
3216
|
var ZERO_IDFA = "00000000-0000-0000-0000-000000000000";
|
|
3317
3217
|
var AdvertisingIdManager = class {
|
|
3318
3218
|
constructor() {
|
|
@@ -3323,7 +3223,7 @@ var AdvertisingIdManager = class {
|
|
|
3323
3223
|
const fallback = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
|
|
3324
3224
|
try {
|
|
3325
3225
|
const tracking = await import("expo-tracking-transparency");
|
|
3326
|
-
if (
|
|
3226
|
+
if (import_react_native9.Platform.OS === "ios") {
|
|
3327
3227
|
if (!tracking.isAvailable()) {
|
|
3328
3228
|
const idfv2 = await this.collectIdfv();
|
|
3329
3229
|
this.cached = { ...fallback, idfv: idfv2 };
|
|
@@ -3342,7 +3242,7 @@ var AdvertisingIdManager = class {
|
|
|
3342
3242
|
this.cached = { idfv, idfa, gaid: null, attStatus: status };
|
|
3343
3243
|
return this.cached;
|
|
3344
3244
|
}
|
|
3345
|
-
if (
|
|
3245
|
+
if (import_react_native9.Platform.OS === "android") {
|
|
3346
3246
|
const androidStatus = await tracking.getTrackingPermissionsAsync();
|
|
3347
3247
|
const optedIn = androidStatus.granted;
|
|
3348
3248
|
const rawGaid = optedIn ? tracking.getAdvertisingId() : null;
|
|
@@ -3378,9 +3278,9 @@ var import_async_storage3 = __toESM(require("@react-native-async-storage/async-s
|
|
|
3378
3278
|
var import_react_native_device_info2 = __toESM(require("react-native-device-info"));
|
|
3379
3279
|
|
|
3380
3280
|
// src/domains/identity/MetaBridge.ts
|
|
3381
|
-
var
|
|
3281
|
+
var import_react_native10 = require("react-native");
|
|
3382
3282
|
var TIMEOUT_MS = 2e3;
|
|
3383
|
-
var NativeBridge =
|
|
3283
|
+
var NativeBridge = import_react_native10.NativeModules.PaywalloFBBridge ?? null;
|
|
3384
3284
|
var MetaBridge = class {
|
|
3385
3285
|
async getAnonymousID() {
|
|
3386
3286
|
if (!NativeBridge) return null;
|
|
@@ -3428,11 +3328,11 @@ var MetaBridge = class {
|
|
|
3428
3328
|
var metaBridge = new MetaBridge();
|
|
3429
3329
|
|
|
3430
3330
|
// src/domains/identity/InstallReferrerManager.ts
|
|
3431
|
-
var
|
|
3331
|
+
var import_react_native11 = require("react-native");
|
|
3432
3332
|
var REFERRER_TIMEOUT_MS = 5e3;
|
|
3433
3333
|
var InstallReferrerManager = class {
|
|
3434
3334
|
async getReferrer() {
|
|
3435
|
-
if (
|
|
3335
|
+
if (import_react_native11.Platform.OS !== "android") {
|
|
3436
3336
|
return this.emptyResult();
|
|
3437
3337
|
}
|
|
3438
3338
|
let timerId;
|
|
@@ -3495,14 +3395,77 @@ var installReferrerManager = new InstallReferrerManager();
|
|
|
3495
3395
|
var import_react_native13 = require("react-native");
|
|
3496
3396
|
init_uuid();
|
|
3497
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
|
+
|
|
3498
3443
|
// src/domains/session/sessionTracking.ts
|
|
3499
3444
|
async function trackSessionStart(apiClient, sessionId, sessionStartedAt) {
|
|
3500
3445
|
const distinctId = identityManager.getDistinctId();
|
|
3501
|
-
await
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
});
|
|
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
|
+
]);
|
|
3506
3469
|
}
|
|
3507
3470
|
async function trackSessionEnd(apiClient, sessionId, durationSeconds, sessionStartedAt) {
|
|
3508
3471
|
const distinctId = identityManager.getDistinctId();
|
|
@@ -3599,6 +3562,9 @@ var SessionManager = class {
|
|
|
3599
3562
|
if (!this.sessionId || !this.sessionStartedAt) {
|
|
3600
3563
|
return;
|
|
3601
3564
|
}
|
|
3565
|
+
if (this.apiClient) {
|
|
3566
|
+
await this.apiClient.flushEventBatch();
|
|
3567
|
+
}
|
|
3602
3568
|
await this.trackSessionEnd();
|
|
3603
3569
|
this.sessionId = null;
|
|
3604
3570
|
this.sessionStartedAt = null;
|
|
@@ -3683,6 +3649,9 @@ var SessionManager = class {
|
|
|
3683
3649
|
async handleBackground() {
|
|
3684
3650
|
this.backgroundTimestamp = Date.now();
|
|
3685
3651
|
await this.trackAppBackground();
|
|
3652
|
+
if (this.apiClient) {
|
|
3653
|
+
await this.apiClient.flushEventBatch();
|
|
3654
|
+
}
|
|
3686
3655
|
}
|
|
3687
3656
|
async checkEmergencyPaywall() {
|
|
3688
3657
|
if (!this.apiClient || !this.emergencyPaywallHandler) {
|
|
@@ -4038,7 +4007,6 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4038
4007
|
]);
|
|
4039
4008
|
this.apiClient = new ApiClient(config.appKey, config.apiUrl ?? "https://paywallo.com.br", config.debug, environment, offlineQueueEnabled, config.timeout);
|
|
4040
4009
|
queueProcessor.initialize(this.apiClient.getHttpClient(), { debug: config.debug });
|
|
4041
|
-
affiliateManager.initialize(this.apiClient, config.debug);
|
|
4042
4010
|
subscriptionManager.init({
|
|
4043
4011
|
serverUrl: this.apiClient.getBaseUrl(),
|
|
4044
4012
|
appKey: config.appKey,
|
|
@@ -4065,6 +4033,12 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4065
4033
|
this.resolveReady = null;
|
|
4066
4034
|
}
|
|
4067
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
|
+
}
|
|
4068
4042
|
if (this.apiClient) {
|
|
4069
4043
|
const apiClientRef = this.apiClient;
|
|
4070
4044
|
if (config.autoPreloadCampaign) {
|
|
@@ -4349,6 +4323,10 @@ var _PaywalloClientClass = class _PaywalloClientClass {
|
|
|
4349
4323
|
registerEmergencyPaywallHandler(h) {
|
|
4350
4324
|
sessionManager.registerEmergencyPaywallHandler(h);
|
|
4351
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
|
+
}
|
|
4352
4330
|
async requireSubscription(paywallPlacement) {
|
|
4353
4331
|
this.ensureInitialized();
|
|
4354
4332
|
if (await this.hasActiveSubscription()) return true;
|
|
@@ -4893,7 +4871,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
4893
4871
|
// src/hooks/useSubscriptionSync.ts
|
|
4894
4872
|
var import_react17 = require("react");
|
|
4895
4873
|
var CACHE_TTL_MS2 = 5 * 60 * 1e3;
|
|
4896
|
-
var ACTIVE_STATUSES = ["active", "
|
|
4874
|
+
var ACTIVE_STATUSES = ["active", "in_grace_period"];
|
|
4897
4875
|
function toDomainSubscriptionInfo(sub) {
|
|
4898
4876
|
return {
|
|
4899
4877
|
id: "",
|
|
@@ -4912,7 +4890,7 @@ function toDomainResponse(status) {
|
|
|
4912
4890
|
return {
|
|
4913
4891
|
hasActiveSubscription: status.hasActiveSubscription,
|
|
4914
4892
|
subscription: status.subscription ? toDomainSubscriptionInfo(status.subscription) : null,
|
|
4915
|
-
entitlements: []
|
|
4893
|
+
entitlements: status.entitlements ?? []
|
|
4916
4894
|
};
|
|
4917
4895
|
}
|
|
4918
4896
|
function isSubscriptionStillActive(sub) {
|
|
@@ -4968,13 +4946,14 @@ function useSubscriptionSync() {
|
|
|
4968
4946
|
const persisted = await subscriptionCache.get(distinctId);
|
|
4969
4947
|
if (persisted && !persisted.isStale) {
|
|
4970
4948
|
const persistedSub = persisted.data.subscription;
|
|
4949
|
+
const persistedStatus = persistedSub?.status;
|
|
4971
4950
|
const sub = persistedSub ? {
|
|
4972
4951
|
productId: persistedSub.productId,
|
|
4973
|
-
status:
|
|
4952
|
+
status: persistedStatus,
|
|
4974
4953
|
expiresAt: persistedSub.expiresAt ?? null,
|
|
4975
4954
|
platform: persistedSub.platform,
|
|
4976
4955
|
autoRenewEnabled: persistedSub.willRenew,
|
|
4977
|
-
inGracePeriod:
|
|
4956
|
+
inGracePeriod: persistedStatus === "in_grace_period"
|
|
4978
4957
|
} : null;
|
|
4979
4958
|
const stillActive = isSubscriptionStillActive(sub);
|
|
4980
4959
|
if (stillActive) {
|
|
@@ -5012,14 +4991,14 @@ function useSubscriptionSync() {
|
|
|
5012
4991
|
const persisted = await subscriptionCache.get(distinctId);
|
|
5013
4992
|
if (!persisted?.data.subscription) return null;
|
|
5014
4993
|
const s = persisted.data.subscription;
|
|
5015
|
-
const
|
|
4994
|
+
const status = s.status;
|
|
5016
4995
|
return {
|
|
5017
4996
|
productId: s.productId,
|
|
5018
|
-
status
|
|
4997
|
+
status,
|
|
5019
4998
|
expiresAt: s.expiresAt ?? null,
|
|
5020
4999
|
platform: s.platform,
|
|
5021
5000
|
autoRenewEnabled: s.willRenew,
|
|
5022
|
-
inGracePeriod:
|
|
5001
|
+
inGracePeriod: status === "in_grace_period"
|
|
5023
5002
|
};
|
|
5024
5003
|
} catch {
|
|
5025
5004
|
return null;
|
|
@@ -5445,10 +5424,7 @@ var Paywallo = PaywalloClient;
|
|
|
5445
5424
|
var index_default = Paywallo;
|
|
5446
5425
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5447
5426
|
0 && (module.exports = {
|
|
5448
|
-
AFFILIATE_ERROR_CODES,
|
|
5449
5427
|
ANALYTICS_ERROR_CODES,
|
|
5450
|
-
AffiliateError,
|
|
5451
|
-
AffiliateManager,
|
|
5452
5428
|
AnalyticsError,
|
|
5453
5429
|
ApiClient,
|
|
5454
5430
|
CAMPAIGN_ERROR_CODES,
|
|
@@ -5466,7 +5442,6 @@ var index_default = Paywallo;
|
|
|
5466
5442
|
PaywallError,
|
|
5467
5443
|
PaywallModal,
|
|
5468
5444
|
Paywallo,
|
|
5469
|
-
PaywalloAffiliate,
|
|
5470
5445
|
PaywalloClient,
|
|
5471
5446
|
PaywalloContext,
|
|
5472
5447
|
PaywalloError,
|
|
@@ -5476,7 +5451,6 @@ var index_default = Paywallo;
|
|
|
5476
5451
|
SessionError,
|
|
5477
5452
|
SessionManager,
|
|
5478
5453
|
SubscriptionCache,
|
|
5479
|
-
affiliateManager,
|
|
5480
5454
|
createPurchaseError,
|
|
5481
5455
|
detectDeviceLanguage,
|
|
5482
5456
|
getCurrentLanguage,
|