@virex-tech/paywallo-sdk 2.4.1 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PaywalloSdk.podspec +1 -1
- package/README.md +45 -4
- package/android/build.gradle +0 -1
- package/android/src/main/java/com/paywallo/sdk/PaywalloFBBridgeModule.kt +7 -0
- package/android/src/main/java/com/paywallo/sdk/PaywalloSdkPackage.kt +1 -2
- package/dist/index.d.mts +298 -176
- package/dist/index.d.ts +298 -176
- package/dist/index.js +977 -912
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +925 -862
- package/dist/index.mjs.map +1 -1
- package/ios/PaywalloFBBridge.m +3 -0
- package/ios/PaywalloFBBridge.swift +20 -0
- package/package.json +4 -1
- package/android/src/main/java/com/paywallo/sdk/PaywalloDeviceModule.kt +0 -148
- package/ios/PaywalloDevice.m +0 -8
- package/ios/PaywalloDevice.swift +0 -119
package/dist/index.mjs
CHANGED
|
@@ -246,77 +246,102 @@ var init_StorageMigration = __esm({
|
|
|
246
246
|
}
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
+
// src/errors/ClientError.ts
|
|
250
|
+
var ClientError, CLIENT_ERROR_CODES;
|
|
251
|
+
var init_ClientError = __esm({
|
|
252
|
+
"src/errors/ClientError.ts"() {
|
|
253
|
+
"use strict";
|
|
254
|
+
init_PaywalloError();
|
|
255
|
+
ClientError = class extends PaywalloError {
|
|
256
|
+
constructor(code, message) {
|
|
257
|
+
super("client", code, message);
|
|
258
|
+
this.name = "ClientError";
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
CLIENT_ERROR_CODES = {
|
|
262
|
+
NOT_INITIALIZED: "CLIENT_NOT_INITIALIZED",
|
|
263
|
+
MISSING_APP_KEY: "CLIENT_MISSING_APP_KEY",
|
|
264
|
+
INVALID_EVENT_NAME: "CLIENT_INVALID_EVENT_NAME",
|
|
265
|
+
PROVIDER_MISSING: "CLIENT_PROVIDER_MISSING",
|
|
266
|
+
INSECURE_REQUEST: "CLIENT_INSECURE_REQUEST",
|
|
267
|
+
UNKNOWN: "CLIENT_UNKNOWN"
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
249
272
|
// src/utils/NativeDeviceInfo.ts
|
|
250
|
-
import {
|
|
273
|
+
import { Platform } from "react-native";
|
|
274
|
+
import * as Device from "expo-device";
|
|
275
|
+
import * as Application from "expo-application";
|
|
276
|
+
import * as Localization from "expo-localization";
|
|
277
|
+
function assertExpoModules() {
|
|
278
|
+
if (!Device || Device.osName === void 0) {
|
|
279
|
+
throw new ClientError(
|
|
280
|
+
"MISSING_EXPO_DEPS",
|
|
281
|
+
"Paywallo SDK 3.x requires expo-device, expo-localization and expo-application. Run: npx expo install expo-device expo-localization expo-application"
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
251
285
|
function setNativeDeviceInfoDebug(debug) {
|
|
252
286
|
_debug2 = debug;
|
|
253
287
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
288
|
+
function buildSyncFields(idfv) {
|
|
289
|
+
const locale = Localization.getLocales()[0] ?? null;
|
|
290
|
+
const calendar = Localization.getCalendars()[0] ?? null;
|
|
291
|
+
const androidId = Platform.OS === "android" ? Application.getAndroidId() ?? "unknown" : "unknown";
|
|
292
|
+
return {
|
|
293
|
+
deviceId: Platform.OS === "ios" ? idfv ?? "unknown" : androidId,
|
|
294
|
+
model: Device.modelName ?? "unknown",
|
|
295
|
+
modelId: Device.modelId ?? Device.modelName ?? "unknown",
|
|
296
|
+
osName: Device.osName ?? Platform.OS,
|
|
297
|
+
systemVersion: Device.osVersion ?? "unknown",
|
|
298
|
+
appVersion: Application.nativeApplicationVersion ?? "unknown",
|
|
299
|
+
buildNumber: Application.nativeBuildVersion ?? "0",
|
|
300
|
+
bundleId: Application.applicationId ?? "unknown",
|
|
301
|
+
brand: Device.brand ?? "unknown",
|
|
302
|
+
idfv,
|
|
303
|
+
regionCode: locale?.regionCode ?? null,
|
|
304
|
+
languageTag: locale?.languageTag ?? null,
|
|
305
|
+
languageCode: locale?.languageCode ?? null,
|
|
306
|
+
timeZone: calendar?.timeZone ?? null
|
|
307
|
+
};
|
|
269
308
|
}
|
|
270
309
|
async function getDeviceInfo() {
|
|
271
310
|
if (cachedDeviceInfo !== null) return cachedDeviceInfo;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
cachedDeviceInfo
|
|
277
|
-
return raw;
|
|
311
|
+
assertExpoModules();
|
|
312
|
+
const idfv = Platform.OS === "ios" ? await Application.getIosIdForVendorAsync() : null;
|
|
313
|
+
if (_debug2) console.log("[Paywallo] device info collected, idfv present:", idfv != null);
|
|
314
|
+
cachedDeviceInfo = buildSyncFields(idfv);
|
|
315
|
+
return cachedDeviceInfo;
|
|
278
316
|
}
|
|
279
317
|
async function getInstallReferrer() {
|
|
280
|
-
const mod = getNativeModule();
|
|
281
|
-
if (!mod) return null;
|
|
282
318
|
try {
|
|
283
|
-
return await
|
|
319
|
+
return await Application.getInstallReferrerAsync();
|
|
284
320
|
} catch {
|
|
285
321
|
return null;
|
|
286
322
|
}
|
|
287
323
|
}
|
|
288
324
|
function isAvailable2() {
|
|
289
|
-
return
|
|
325
|
+
return typeof Device !== "undefined" && Device.osName !== void 0;
|
|
290
326
|
}
|
|
291
327
|
function clearCache() {
|
|
292
328
|
cachedDeviceInfo = null;
|
|
293
329
|
}
|
|
294
330
|
function getCachedDeviceInfo() {
|
|
295
|
-
return cachedDeviceInfo;
|
|
331
|
+
if (cachedDeviceInfo !== null) return cachedDeviceInfo;
|
|
332
|
+
try {
|
|
333
|
+
assertExpoModules();
|
|
334
|
+
return buildSyncFields(null);
|
|
335
|
+
} catch {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
296
338
|
}
|
|
297
|
-
var
|
|
339
|
+
var _debug2, cachedDeviceInfo, nativeDeviceInfo;
|
|
298
340
|
var init_NativeDeviceInfo = __esm({
|
|
299
341
|
"src/utils/NativeDeviceInfo.ts"() {
|
|
300
342
|
"use strict";
|
|
301
|
-
|
|
302
|
-
deviceId: "unknown",
|
|
303
|
-
model: "unknown",
|
|
304
|
-
modelId: "unknown",
|
|
305
|
-
systemVersion: "0.0.0",
|
|
306
|
-
appVersion: "0.0.0",
|
|
307
|
-
buildNumber: "0",
|
|
308
|
-
bundleId: "unknown",
|
|
309
|
-
brand: "unknown",
|
|
310
|
-
systemName: "unknown",
|
|
311
|
-
totalDisk: 0,
|
|
312
|
-
freeDisk: 0,
|
|
313
|
-
totalRam: 0,
|
|
314
|
-
carrier: "unknown",
|
|
315
|
-
installerPackage: null,
|
|
316
|
-
idfv: null
|
|
317
|
-
};
|
|
343
|
+
init_ClientError();
|
|
318
344
|
_debug2 = false;
|
|
319
|
-
warnedOnce = false;
|
|
320
345
|
cachedDeviceInfo = null;
|
|
321
346
|
nativeDeviceInfo = {
|
|
322
347
|
getDeviceInfo,
|
|
@@ -331,6 +356,7 @@ var init_NativeDeviceInfo = __esm({
|
|
|
331
356
|
// src/utils/uuid.ts
|
|
332
357
|
var uuid_exports = {};
|
|
333
358
|
__export(uuid_exports, {
|
|
359
|
+
deterministicUUID: () => deterministicUUID,
|
|
334
360
|
generateUUID: () => generateUUID,
|
|
335
361
|
isValidUUIDv4: () => isValidUUIDv4
|
|
336
362
|
});
|
|
@@ -342,6 +368,28 @@ function generateUUID() {
|
|
|
342
368
|
return v.toString(16);
|
|
343
369
|
});
|
|
344
370
|
}
|
|
371
|
+
function deterministicUUID(seed) {
|
|
372
|
+
const fnv1a32 = (s, basis) => {
|
|
373
|
+
let h = basis >>> 0;
|
|
374
|
+
for (let i = 0; i < s.length; i++) {
|
|
375
|
+
h = Math.imul(h ^ s.charCodeAt(i), 16777619) >>> 0;
|
|
376
|
+
}
|
|
377
|
+
return h;
|
|
378
|
+
};
|
|
379
|
+
const B = 2166136261;
|
|
380
|
+
const h0 = fnv1a32(seed, B);
|
|
381
|
+
const h1 = fnv1a32(seed, B ^ 252645135);
|
|
382
|
+
const h2 = fnv1a32(seed, B ^ 4042322160);
|
|
383
|
+
const h3 = fnv1a32(seed, B ^ 2863311530);
|
|
384
|
+
const x = (n, len) => (n >>> 0).toString(16).padStart(len, "0").slice(-len);
|
|
385
|
+
const s1 = x(h0, 8);
|
|
386
|
+
const s2 = x(h1 >>> 16, 4);
|
|
387
|
+
const s3 = "4" + x(h1 & 4095, 3);
|
|
388
|
+
const vb = (8 | h2 >>> 30 & 3).toString(16);
|
|
389
|
+
const s4 = vb + x(h2 >>> 18 & 4095, 3);
|
|
390
|
+
const s5 = x(h2 & 65535, 4) + x(h3, 8);
|
|
391
|
+
return `${s1}-${s2}-${s3}-${s4}-${s5}`;
|
|
392
|
+
}
|
|
345
393
|
function isValidUUIDv4(value) {
|
|
346
394
|
if (!value) return false;
|
|
347
395
|
return UUID_V4_REGEX.test(value);
|
|
@@ -609,6 +657,10 @@ var init_IdentityManager = __esm({
|
|
|
609
657
|
if (!this.initialized) return "";
|
|
610
658
|
return this.distinctId ?? this.anonId ?? "";
|
|
611
659
|
}
|
|
660
|
+
/** Public stable identifier — returns the same value as `getDistinctId()`. */
|
|
661
|
+
getId() {
|
|
662
|
+
return this.getDistinctId();
|
|
663
|
+
}
|
|
612
664
|
getDeviceId() {
|
|
613
665
|
return this.deviceId;
|
|
614
666
|
}
|
|
@@ -880,7 +932,7 @@ var init_campaign = __esm({
|
|
|
880
932
|
});
|
|
881
933
|
|
|
882
934
|
// src/domains/identity/AdvertisingIdManager.ts
|
|
883
|
-
import { Platform } from "react-native";
|
|
935
|
+
import { Platform as Platform2 } from "react-native";
|
|
884
936
|
var ZERO_IDFA, AdvertisingIdManager, advertisingIdManager;
|
|
885
937
|
var init_AdvertisingIdManager = __esm({
|
|
886
938
|
"src/domains/identity/AdvertisingIdManager.ts"() {
|
|
@@ -904,7 +956,7 @@ var init_AdvertisingIdManager = __esm({
|
|
|
904
956
|
const fallback = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
|
|
905
957
|
try {
|
|
906
958
|
const tracking = await import("expo-tracking-transparency");
|
|
907
|
-
if (
|
|
959
|
+
if (Platform2.OS === "ios") {
|
|
908
960
|
if (!tracking.isAvailable()) {
|
|
909
961
|
const idfv2 = await this.collectIdfv();
|
|
910
962
|
const result2 = { ...fallback, idfv: idfv2 };
|
|
@@ -925,7 +977,7 @@ var init_AdvertisingIdManager = __esm({
|
|
|
925
977
|
if (idfv !== null) this.cached = result;
|
|
926
978
|
return result;
|
|
927
979
|
}
|
|
928
|
-
if (
|
|
980
|
+
if (Platform2.OS === "android") {
|
|
929
981
|
const rawGaid = tracking.getAdvertisingId();
|
|
930
982
|
const gaid = this.sanitizeId(rawGaid);
|
|
931
983
|
this.cached = { idfv: null, idfa: null, gaid, attStatus: "unavailable" };
|
|
@@ -1012,10 +1064,8 @@ async function collectDeviceInfo() {
|
|
|
1012
1064
|
const result = await nativeDeviceInfo.getDeviceInfo();
|
|
1013
1065
|
return {
|
|
1014
1066
|
appVersion: result.appVersion,
|
|
1015
|
-
deviceModel: result.
|
|
1016
|
-
osVersion: result.systemVersion
|
|
1017
|
-
darwinVersion: result.darwinVersion,
|
|
1018
|
-
webkitVersion: result.webkitVersion
|
|
1067
|
+
deviceModel: result.modelId,
|
|
1068
|
+
osVersion: result.systemVersion
|
|
1019
1069
|
};
|
|
1020
1070
|
}
|
|
1021
1071
|
var init_deviceInfo = __esm({
|
|
@@ -1410,6 +1460,12 @@ async function markInstallTracked(storage, installedAt) {
|
|
|
1410
1460
|
} catch {
|
|
1411
1461
|
}
|
|
1412
1462
|
}
|
|
1463
|
+
async function resolveInstallEventId(deviceKey, appKey) {
|
|
1464
|
+
if (deviceKey && deviceKey.trim().length > 0) {
|
|
1465
|
+
return deterministicUUID(`${appKey}:${deviceKey}`);
|
|
1466
|
+
}
|
|
1467
|
+
return getOrCreateInstallEventId();
|
|
1468
|
+
}
|
|
1413
1469
|
async function getOrCreateInstallEventId() {
|
|
1414
1470
|
const existing = await nativeStorage.get(INSTALL_KEYS.INSTALL_EVENT_ID);
|
|
1415
1471
|
if (existing) return existing;
|
|
@@ -1430,6 +1486,7 @@ var init_InstallIdempotency = __esm({
|
|
|
1430
1486
|
"src/domains/identity/InstallIdempotency.ts"() {
|
|
1431
1487
|
"use strict";
|
|
1432
1488
|
init_NativeStorage();
|
|
1489
|
+
init_uuid();
|
|
1433
1490
|
INSTALL_KEYS = {
|
|
1434
1491
|
/** Primary flag — set AFTER a successful $app_installed dispatch. */
|
|
1435
1492
|
INSTALL_TRACKED: "@paywallo:install_tracked",
|
|
@@ -1454,18 +1511,180 @@ var init_InstallIdempotency = __esm({
|
|
|
1454
1511
|
}
|
|
1455
1512
|
});
|
|
1456
1513
|
|
|
1514
|
+
// src/domains/identity/MetaBridge.ts
|
|
1515
|
+
import { NativeModules as NativeModules2 } from "react-native";
|
|
1516
|
+
var TIMEOUT_MS, NativeBridge, MetaBridge, metaBridge;
|
|
1517
|
+
var init_MetaBridge = __esm({
|
|
1518
|
+
"src/domains/identity/MetaBridge.ts"() {
|
|
1519
|
+
"use strict";
|
|
1520
|
+
TIMEOUT_MS = 2e3;
|
|
1521
|
+
NativeBridge = NativeModules2.PaywalloFBBridge ?? null;
|
|
1522
|
+
MetaBridge = class {
|
|
1523
|
+
constructor() {
|
|
1524
|
+
this.cachedAnonId = null;
|
|
1525
|
+
this.cachedDeferredLink = null;
|
|
1526
|
+
this.deferredLinkFetched = false;
|
|
1527
|
+
this.debug = false;
|
|
1528
|
+
}
|
|
1529
|
+
setDebug(debug) {
|
|
1530
|
+
this.debug = debug;
|
|
1531
|
+
}
|
|
1532
|
+
/** Sync read of the cached anonymous ID. Returns null until `getAnonymousID()` resolves once. */
|
|
1533
|
+
getCachedAnonymousID() {
|
|
1534
|
+
return this.cachedAnonId;
|
|
1535
|
+
}
|
|
1536
|
+
async getAnonymousID() {
|
|
1537
|
+
if (this.cachedAnonId) return this.cachedAnonId;
|
|
1538
|
+
if (!NativeBridge) return null;
|
|
1539
|
+
try {
|
|
1540
|
+
let timerId;
|
|
1541
|
+
const timeout = new Promise((resolve) => {
|
|
1542
|
+
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
1543
|
+
});
|
|
1544
|
+
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
1545
|
+
clearTimeout(timerId);
|
|
1546
|
+
if (result) this.cachedAnonId = result;
|
|
1547
|
+
return result;
|
|
1548
|
+
} catch {
|
|
1549
|
+
return null;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
async fetchDeferredAppLink() {
|
|
1553
|
+
if (this.deferredLinkFetched) return this.cachedDeferredLink;
|
|
1554
|
+
if (!NativeBridge) return null;
|
|
1555
|
+
if (typeof NativeBridge.fetchDeferredAppLink !== "function") return null;
|
|
1556
|
+
try {
|
|
1557
|
+
let timerId;
|
|
1558
|
+
const timeout = new Promise((resolve) => {
|
|
1559
|
+
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
1560
|
+
});
|
|
1561
|
+
const result = await Promise.race([
|
|
1562
|
+
NativeBridge.fetchDeferredAppLink().catch(() => null),
|
|
1563
|
+
timeout
|
|
1564
|
+
]);
|
|
1565
|
+
clearTimeout(timerId);
|
|
1566
|
+
this.deferredLinkFetched = true;
|
|
1567
|
+
this.cachedDeferredLink = result;
|
|
1568
|
+
return result;
|
|
1569
|
+
} catch {
|
|
1570
|
+
this.deferredLinkFetched = true;
|
|
1571
|
+
this.cachedDeferredLink = null;
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
async logEvent(name, params = {}) {
|
|
1576
|
+
if (!NativeBridge) return;
|
|
1577
|
+
try {
|
|
1578
|
+
await NativeBridge.logEvent(name, params);
|
|
1579
|
+
} catch (error) {
|
|
1580
|
+
console.error("[Paywallo:MetaBridge] logEvent failed", { name, error });
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
async logPurchase(amount, currency, params = {}) {
|
|
1584
|
+
if (!NativeBridge) return;
|
|
1585
|
+
try {
|
|
1586
|
+
await NativeBridge.logPurchase(amount, currency, params);
|
|
1587
|
+
} catch (error) {
|
|
1588
|
+
console.error("[Paywallo:MetaBridge] logPurchase failed", { amount, currency, error });
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
setUserID(userId) {
|
|
1592
|
+
if (!NativeBridge) return;
|
|
1593
|
+
try {
|
|
1594
|
+
NativeBridge.setUserID(userId);
|
|
1595
|
+
} catch (error) {
|
|
1596
|
+
console.error("[Paywallo:MetaBridge] setUserID failed", { error });
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
flush() {
|
|
1600
|
+
if (!NativeBridge) return;
|
|
1601
|
+
try {
|
|
1602
|
+
NativeBridge.flush();
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
console.error("[Paywallo:MetaBridge] flush failed", { error });
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
};
|
|
1608
|
+
metaBridge = new MetaBridge();
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
// src/domains/identity/deferredAppLink.ts
|
|
1613
|
+
function parseQuery(s) {
|
|
1614
|
+
const result = {};
|
|
1615
|
+
for (const pair of s.split("&")) {
|
|
1616
|
+
const eqIndex = pair.indexOf("=");
|
|
1617
|
+
if (eqIndex === -1) continue;
|
|
1618
|
+
try {
|
|
1619
|
+
const key = decodeURIComponent(pair.slice(0, eqIndex).replace(/\+/g, " "));
|
|
1620
|
+
const value = decodeURIComponent(pair.slice(eqIndex + 1).replace(/\+/g, " "));
|
|
1621
|
+
if (key) result[key] = value;
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return result;
|
|
1626
|
+
}
|
|
1627
|
+
function parseDeferredAppLink(url) {
|
|
1628
|
+
if (!url || url.trim() === "") return null;
|
|
1629
|
+
const raw = url.slice(0, 2048);
|
|
1630
|
+
const cleanRaw = raw.split("#")[0];
|
|
1631
|
+
const qIndex = cleanRaw.indexOf("?");
|
|
1632
|
+
if (qIndex === -1) return null;
|
|
1633
|
+
const topParams = parseQuery(cleanRaw.slice(qIndex + 1));
|
|
1634
|
+
let fbclid = nz(topParams["fbclid"]);
|
|
1635
|
+
let utmSource = nz(topParams["utm_source"]);
|
|
1636
|
+
let utmMedium = nz(topParams["utm_medium"]);
|
|
1637
|
+
let utmCampaign = nz(topParams["utm_campaign"]);
|
|
1638
|
+
let ttclid = nz(topParams["ttclid"]);
|
|
1639
|
+
let trackingId = nz(topParams["tracking_id"]);
|
|
1640
|
+
let targetUrl = null;
|
|
1641
|
+
if (topParams["target_url"]) {
|
|
1642
|
+
try {
|
|
1643
|
+
targetUrl = decodeURIComponent(topParams["target_url"]);
|
|
1644
|
+
} catch {
|
|
1645
|
+
targetUrl = topParams["target_url"];
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
if (!fbclid && targetUrl) {
|
|
1649
|
+
const cleanTargetUrl = targetUrl.split("#")[0];
|
|
1650
|
+
const innerQ = cleanTargetUrl.indexOf("?");
|
|
1651
|
+
if (innerQ !== -1) {
|
|
1652
|
+
const inner = parseQuery(cleanTargetUrl.slice(innerQ + 1));
|
|
1653
|
+
fbclid = fbclid ?? nz(inner["fbclid"]);
|
|
1654
|
+
utmSource = utmSource ?? nz(inner["utm_source"]);
|
|
1655
|
+
utmMedium = utmMedium ?? nz(inner["utm_medium"]);
|
|
1656
|
+
utmCampaign = utmCampaign ?? nz(inner["utm_campaign"]);
|
|
1657
|
+
ttclid = ttclid ?? nz(inner["ttclid"]);
|
|
1658
|
+
trackingId = trackingId ?? nz(inner["tracking_id"]);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
if (!fbclid && !ttclid && !trackingId && !utmSource && !utmMedium && !utmCampaign) {
|
|
1662
|
+
return null;
|
|
1663
|
+
}
|
|
1664
|
+
return { fbclid, utmSource, utmMedium, utmCampaign, ttclid, trackingId, targetUrl, raw };
|
|
1665
|
+
}
|
|
1666
|
+
var nz;
|
|
1667
|
+
var init_deferredAppLink = __esm({
|
|
1668
|
+
"src/domains/identity/deferredAppLink.ts"() {
|
|
1669
|
+
"use strict";
|
|
1670
|
+
nz = (v) => typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1457
1674
|
// src/domains/identity/InstallReferrerManager.ts
|
|
1458
|
-
import { Platform as
|
|
1675
|
+
import { Platform as Platform3 } from "react-native";
|
|
1459
1676
|
var REFERRER_TIMEOUT_MS, InstallReferrerManager, installReferrerManager;
|
|
1460
1677
|
var init_InstallReferrerManager = __esm({
|
|
1461
1678
|
"src/domains/identity/InstallReferrerManager.ts"() {
|
|
1462
1679
|
"use strict";
|
|
1463
1680
|
init_NativeDeviceInfo();
|
|
1681
|
+
init_MetaBridge();
|
|
1682
|
+
init_deferredAppLink();
|
|
1464
1683
|
REFERRER_TIMEOUT_MS = 5e3;
|
|
1465
1684
|
InstallReferrerManager = class {
|
|
1466
1685
|
async getReferrer() {
|
|
1467
|
-
if (
|
|
1468
|
-
return this.
|
|
1686
|
+
if (Platform3.OS !== "android") {
|
|
1687
|
+
return this.fetchDeferredReferrer();
|
|
1469
1688
|
}
|
|
1470
1689
|
let timerId;
|
|
1471
1690
|
const timeoutPromise = new Promise((resolve) => {
|
|
@@ -1476,6 +1695,29 @@ var init_InstallReferrerManager = __esm({
|
|
|
1476
1695
|
clearTimeout(timerId);
|
|
1477
1696
|
return result;
|
|
1478
1697
|
}
|
|
1698
|
+
async fetchDeferredReferrer() {
|
|
1699
|
+
try {
|
|
1700
|
+
const url = await metaBridge.fetchDeferredAppLink();
|
|
1701
|
+
const parsed = parseDeferredAppLink(url);
|
|
1702
|
+
if (!parsed) return this.emptyResult();
|
|
1703
|
+
return {
|
|
1704
|
+
rawReferrer: parsed.targetUrl ?? parsed.raw,
|
|
1705
|
+
trackingId: parsed.trackingId,
|
|
1706
|
+
fbclid: parsed.fbclid,
|
|
1707
|
+
utmSource: parsed.utmSource,
|
|
1708
|
+
utmMedium: parsed.utmMedium,
|
|
1709
|
+
utmCampaign: parsed.utmCampaign,
|
|
1710
|
+
ttclid: parsed.ttclid,
|
|
1711
|
+
tiktokCampaignId: null,
|
|
1712
|
+
tiktokAdgroupId: null,
|
|
1713
|
+
tiktokAdId: null,
|
|
1714
|
+
installReferrerRaw: parsed.raw,
|
|
1715
|
+
installReferrerSource: "meta_deferred"
|
|
1716
|
+
};
|
|
1717
|
+
} catch {
|
|
1718
|
+
return this.emptyResult();
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1479
1721
|
async fetchReferrer() {
|
|
1480
1722
|
try {
|
|
1481
1723
|
const referrer = await nativeDeviceInfo.getInstallReferrer();
|
|
@@ -1536,81 +1778,8 @@ var init_InstallReferrerManager = __esm({
|
|
|
1536
1778
|
}
|
|
1537
1779
|
});
|
|
1538
1780
|
|
|
1539
|
-
// src/domains/identity/MetaBridge.ts
|
|
1540
|
-
import { NativeModules as NativeModules3 } from "react-native";
|
|
1541
|
-
var TIMEOUT_MS, NativeBridge, MetaBridge, metaBridge;
|
|
1542
|
-
var init_MetaBridge = __esm({
|
|
1543
|
-
"src/domains/identity/MetaBridge.ts"() {
|
|
1544
|
-
"use strict";
|
|
1545
|
-
TIMEOUT_MS = 2e3;
|
|
1546
|
-
NativeBridge = NativeModules3.PaywalloFBBridge ?? null;
|
|
1547
|
-
MetaBridge = class {
|
|
1548
|
-
constructor() {
|
|
1549
|
-
this.cachedAnonId = null;
|
|
1550
|
-
this.debug = false;
|
|
1551
|
-
}
|
|
1552
|
-
setDebug(debug) {
|
|
1553
|
-
this.debug = debug;
|
|
1554
|
-
}
|
|
1555
|
-
/** Sync read of the cached anonymous ID. Returns null until `getAnonymousID()` resolves once. */
|
|
1556
|
-
getCachedAnonymousID() {
|
|
1557
|
-
return this.cachedAnonId;
|
|
1558
|
-
}
|
|
1559
|
-
async getAnonymousID() {
|
|
1560
|
-
if (this.cachedAnonId) return this.cachedAnonId;
|
|
1561
|
-
if (!NativeBridge) return null;
|
|
1562
|
-
try {
|
|
1563
|
-
let timerId;
|
|
1564
|
-
const timeout = new Promise((resolve) => {
|
|
1565
|
-
timerId = setTimeout(() => resolve(null), TIMEOUT_MS);
|
|
1566
|
-
});
|
|
1567
|
-
const result = await Promise.race([NativeBridge.getAnonymousID(), timeout]);
|
|
1568
|
-
clearTimeout(timerId);
|
|
1569
|
-
if (result) this.cachedAnonId = result;
|
|
1570
|
-
return result;
|
|
1571
|
-
} catch {
|
|
1572
|
-
return null;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
async logEvent(name, params = {}) {
|
|
1576
|
-
if (!NativeBridge) return;
|
|
1577
|
-
try {
|
|
1578
|
-
await NativeBridge.logEvent(name, params);
|
|
1579
|
-
} catch (error) {
|
|
1580
|
-
console.error("[Paywallo:MetaBridge] logEvent failed", { name, error });
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
async logPurchase(amount, currency, params = {}) {
|
|
1584
|
-
if (!NativeBridge) return;
|
|
1585
|
-
try {
|
|
1586
|
-
await NativeBridge.logPurchase(amount, currency, params);
|
|
1587
|
-
} catch (error) {
|
|
1588
|
-
console.error("[Paywallo:MetaBridge] logPurchase failed", { amount, currency, error });
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
setUserID(userId) {
|
|
1592
|
-
if (!NativeBridge) return;
|
|
1593
|
-
try {
|
|
1594
|
-
NativeBridge.setUserID(userId);
|
|
1595
|
-
} catch (error) {
|
|
1596
|
-
console.error("[Paywallo:MetaBridge] setUserID failed", { error });
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
flush() {
|
|
1600
|
-
if (!NativeBridge) return;
|
|
1601
|
-
try {
|
|
1602
|
-
NativeBridge.flush();
|
|
1603
|
-
} catch (error) {
|
|
1604
|
-
console.error("[Paywallo:MetaBridge] flush failed", { error });
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
};
|
|
1608
|
-
metaBridge = new MetaBridge();
|
|
1609
|
-
}
|
|
1610
|
-
});
|
|
1611
|
-
|
|
1612
1781
|
// src/domains/identity/InstallTracker.ts
|
|
1613
|
-
import { Dimensions, PixelRatio, Platform as
|
|
1782
|
+
import { Dimensions, PixelRatio, Platform as Platform4 } from "react-native";
|
|
1614
1783
|
var InstallTracker;
|
|
1615
1784
|
var init_InstallTracker = __esm({
|
|
1616
1785
|
"src/domains/identity/InstallTracker.ts"() {
|
|
@@ -1678,44 +1847,17 @@ var init_InstallTracker = __esm({
|
|
|
1678
1847
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? "unknown";
|
|
1679
1848
|
const info = await nativeDeviceInfo.getDeviceInfo();
|
|
1680
1849
|
const deviceModel = info.modelId || info.model || "unknown";
|
|
1681
|
-
const
|
|
1850
|
+
const osVersion2 = info.systemVersion || "unknown";
|
|
1682
1851
|
const appVersion = info.appVersion || "unknown";
|
|
1683
1852
|
const buildNumber = info.buildNumber || "0";
|
|
1684
|
-
let
|
|
1685
|
-
try {
|
|
1686
|
-
carrier = info.carrier ?? "unknown";
|
|
1687
|
-
} catch {
|
|
1688
|
-
}
|
|
1689
|
-
let totalDisk = 0;
|
|
1690
|
-
try {
|
|
1691
|
-
totalDisk = Number(info.totalDisk) || 0;
|
|
1692
|
-
} catch {
|
|
1693
|
-
}
|
|
1694
|
-
let freeDisk = 0;
|
|
1695
|
-
try {
|
|
1696
|
-
freeDisk = Number(info.freeDisk) || 0;
|
|
1697
|
-
} catch {
|
|
1698
|
-
}
|
|
1699
|
-
let totalRam = 0;
|
|
1700
|
-
try {
|
|
1701
|
-
totalRam = Number(info.totalRam) || 0;
|
|
1702
|
-
} catch {
|
|
1703
|
-
}
|
|
1704
|
-
let brand = "unknown";
|
|
1705
|
-
try {
|
|
1706
|
-
brand = info.brand ?? "unknown";
|
|
1707
|
-
} catch {
|
|
1708
|
-
}
|
|
1709
|
-
let installerPackage = null;
|
|
1853
|
+
let brand2 = "unknown";
|
|
1710
1854
|
try {
|
|
1711
|
-
|
|
1712
|
-
installerPackage = info.installerPackage ?? null;
|
|
1713
|
-
}
|
|
1855
|
+
brand2 = info.brand ?? "unknown";
|
|
1714
1856
|
} catch {
|
|
1715
1857
|
}
|
|
1716
1858
|
deviceData = {
|
|
1717
1859
|
deviceModel,
|
|
1718
|
-
osVersion,
|
|
1860
|
+
osVersion: osVersion2,
|
|
1719
1861
|
appVersion,
|
|
1720
1862
|
buildNumber,
|
|
1721
1863
|
...screenWidth > 0 && { screenWidth },
|
|
@@ -1723,21 +1865,20 @@ var init_InstallTracker = __esm({
|
|
|
1723
1865
|
...screenDensity > 0 && { screenDensity },
|
|
1724
1866
|
timezone,
|
|
1725
1867
|
locale,
|
|
1726
|
-
...
|
|
1727
|
-
...
|
|
1728
|
-
...freeDisk > 0 && { freeDisk },
|
|
1729
|
-
...totalRam > 0 && { totalRam },
|
|
1730
|
-
...brand !== "unknown" && { brand },
|
|
1731
|
-
...installerPackage && { installerPackage }
|
|
1868
|
+
...brand2 !== "unknown" && { brand: brand2 },
|
|
1869
|
+
...info.regionCode && { country: info.regionCode }
|
|
1732
1870
|
};
|
|
1733
1871
|
} catch {
|
|
1734
1872
|
}
|
|
1735
|
-
const [fbAnonId, referrer, adIds
|
|
1873
|
+
const [fbAnonId, referrer, adIds] = await Promise.all([
|
|
1736
1874
|
metaBridge.getAnonymousID(),
|
|
1737
1875
|
installReferrerManager.getReferrer(),
|
|
1738
|
-
this.advertisingIdManager.collect(requestATT)
|
|
1739
|
-
getOrCreateInstallEventId()
|
|
1876
|
+
this.advertisingIdManager.collect(requestATT)
|
|
1740
1877
|
]);
|
|
1878
|
+
const installEventId = await resolveInstallEventId(
|
|
1879
|
+
adIds.idfv ?? adIds.gaid ?? null,
|
|
1880
|
+
apiClient.getAppKey()
|
|
1881
|
+
);
|
|
1741
1882
|
if (referrer.fbclid || referrer.utmSource || referrer.utmMedium || referrer.utmCampaign || referrer.ttclid || referrer.tiktokCampaignId || referrer.tiktokAdgroupId || referrer.tiktokAdId) {
|
|
1742
1883
|
attributionTracker.capture({
|
|
1743
1884
|
...referrer.fbclid && { fbclid: referrer.fbclid },
|
|
@@ -1768,7 +1909,7 @@ var init_InstallTracker = __esm({
|
|
|
1768
1909
|
}
|
|
1769
1910
|
await apiClient.trackEvent("$app_installed", distinctId, {
|
|
1770
1911
|
installedAt,
|
|
1771
|
-
platform:
|
|
1912
|
+
platform: Platform4.OS,
|
|
1772
1913
|
installEventId,
|
|
1773
1914
|
...sessionId && { sessionId },
|
|
1774
1915
|
...deviceData,
|
|
@@ -1808,7 +1949,7 @@ var init_InstallTracker = __esm({
|
|
|
1808
1949
|
method: "POST",
|
|
1809
1950
|
headers: { "Content-Type": "application/json", "X-App-Key": appKey },
|
|
1810
1951
|
body: JSON.stringify({
|
|
1811
|
-
platform:
|
|
1952
|
+
platform: Platform4.OS,
|
|
1812
1953
|
...adIds.idfv && { idfv: adIds.idfv },
|
|
1813
1954
|
...adIds.gaid && { gaid: adIds.gaid },
|
|
1814
1955
|
...referrer.rawReferrer && { installReferrer: referrer.rawReferrer },
|
|
@@ -1818,6 +1959,7 @@ var init_InstallTracker = __esm({
|
|
|
1818
1959
|
screenHeight: deviceData.screenHeight,
|
|
1819
1960
|
timezone: deviceData.timezone,
|
|
1820
1961
|
language: deviceData.locale,
|
|
1962
|
+
...deviceData.country && { country: deviceData.country },
|
|
1821
1963
|
fbAnonId: anonId,
|
|
1822
1964
|
installTimestamp: new Date(installedAt).toISOString()
|
|
1823
1965
|
}),
|
|
@@ -1938,12 +2080,12 @@ var init_identity = __esm({
|
|
|
1938
2080
|
});
|
|
1939
2081
|
|
|
1940
2082
|
// src/domains/notifications/bridges/NativePushBridge.ts
|
|
1941
|
-
import { NativeEventEmitter, NativeModules as
|
|
2083
|
+
import { NativeEventEmitter, NativeModules as NativeModules3, Platform as Platform5 } from "react-native";
|
|
1942
2084
|
function getPaywalloNotifications() {
|
|
1943
|
-
return
|
|
2085
|
+
return NativeModules3.PaywalloNotifications ?? null;
|
|
1944
2086
|
}
|
|
1945
2087
|
function isNativePushAvailable() {
|
|
1946
|
-
return !!
|
|
2088
|
+
return !!NativeModules3.PaywalloNotifications;
|
|
1947
2089
|
}
|
|
1948
2090
|
function mapStatusToNumber(status) {
|
|
1949
2091
|
switch (status) {
|
|
@@ -1965,7 +2107,7 @@ function mapStatusToNumber(status) {
|
|
|
1965
2107
|
}
|
|
1966
2108
|
function getEmitter() {
|
|
1967
2109
|
if (_emitter) return _emitter;
|
|
1968
|
-
const nativeMod =
|
|
2110
|
+
const nativeMod = NativeModules3.PaywalloNotifications;
|
|
1969
2111
|
if (!nativeMod) return null;
|
|
1970
2112
|
_emitter = new NativeEventEmitter(nativeMod);
|
|
1971
2113
|
return _emitter;
|
|
@@ -1986,7 +2128,7 @@ var init_NativePushBridge = __esm({
|
|
|
1986
2128
|
}
|
|
1987
2129
|
}
|
|
1988
2130
|
async getAPNSToken() {
|
|
1989
|
-
if (
|
|
2131
|
+
if (Platform5.OS !== "ios") return null;
|
|
1990
2132
|
return this.getToken();
|
|
1991
2133
|
}
|
|
1992
2134
|
async requestPermission(options) {
|
|
@@ -2220,7 +2362,7 @@ var init_ForegroundHandler = __esm({
|
|
|
2220
2362
|
});
|
|
2221
2363
|
|
|
2222
2364
|
// src/domains/notifications/NotificationEventTracker.ts
|
|
2223
|
-
import { Platform as
|
|
2365
|
+
import { Platform as Platform6 } from "react-native";
|
|
2224
2366
|
function getTimezone() {
|
|
2225
2367
|
try {
|
|
2226
2368
|
return Intl.DateTimeFormat().resolvedOptions().timeZone ?? "UTC";
|
|
@@ -2229,7 +2371,7 @@ function getTimezone() {
|
|
|
2229
2371
|
}
|
|
2230
2372
|
}
|
|
2231
2373
|
function detectPlatform() {
|
|
2232
|
-
return
|
|
2374
|
+
return Platform6.OS === "ios" ? "ios" : "android";
|
|
2233
2375
|
}
|
|
2234
2376
|
var SEEN_MESSAGES_KEY, LEGACY_SEEN_MESSAGES_KEY, SEEN_TTL_MS, MAX_SEEN_SIZE, NOTIFICATION_TYPE_TO_FAMILY, NotificationEventTracker;
|
|
2235
2377
|
var init_NotificationEventTracker = __esm({
|
|
@@ -2405,8 +2547,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2405
2547
|
// src/core/version.ts
|
|
2406
2548
|
function resolveVersion() {
|
|
2407
2549
|
try {
|
|
2408
|
-
if ("2.
|
|
2409
|
-
return "2.
|
|
2550
|
+
if ("2.5.1") {
|
|
2551
|
+
return "2.5.1";
|
|
2410
2552
|
}
|
|
2411
2553
|
} catch {
|
|
2412
2554
|
}
|
|
@@ -2421,7 +2563,7 @@ var init_version = __esm({
|
|
|
2421
2563
|
});
|
|
2422
2564
|
|
|
2423
2565
|
// src/domains/notifications/utils.ts
|
|
2424
|
-
import { Platform as
|
|
2566
|
+
import { Platform as Platform7 } from "react-native";
|
|
2425
2567
|
function sleep(ms, signal) {
|
|
2426
2568
|
return new Promise((resolve, reject) => {
|
|
2427
2569
|
if (signal?.aborted) {
|
|
@@ -2449,8 +2591,8 @@ async function getLocale() {
|
|
|
2449
2591
|
return clampLocale(raw);
|
|
2450
2592
|
} catch {
|
|
2451
2593
|
try {
|
|
2452
|
-
const { getLocales } = __require("expo-localization");
|
|
2453
|
-
const code =
|
|
2594
|
+
const { getLocales: getLocales2 } = __require("expo-localization");
|
|
2595
|
+
const code = getLocales2()[0]?.languageCode ?? "en";
|
|
2454
2596
|
return clampLocale(code);
|
|
2455
2597
|
} catch {
|
|
2456
2598
|
return "en";
|
|
@@ -2477,7 +2619,7 @@ function mapPermissionStatus(status) {
|
|
|
2477
2619
|
}
|
|
2478
2620
|
}
|
|
2479
2621
|
function detectPlatform2() {
|
|
2480
|
-
return
|
|
2622
|
+
return Platform7.OS === "ios" ? "ios" : "android";
|
|
2481
2623
|
}
|
|
2482
2624
|
async function getAppVersion() {
|
|
2483
2625
|
try {
|
|
@@ -2654,7 +2796,7 @@ var init_NotificationTokenOps = __esm({
|
|
|
2654
2796
|
});
|
|
2655
2797
|
|
|
2656
2798
|
// src/domains/notifications/PermissionManager.ts
|
|
2657
|
-
import { Platform as
|
|
2799
|
+
import { Platform as Platform8 } from "react-native";
|
|
2658
2800
|
function mapPermissionStatus2(status) {
|
|
2659
2801
|
switch (status) {
|
|
2660
2802
|
case AUTH_STATUS2.AUTHORIZED:
|
|
@@ -2668,7 +2810,7 @@ function mapPermissionStatus2(status) {
|
|
|
2668
2810
|
}
|
|
2669
2811
|
}
|
|
2670
2812
|
function getPlatform() {
|
|
2671
|
-
return
|
|
2813
|
+
return Platform8;
|
|
2672
2814
|
}
|
|
2673
2815
|
function needsAndroidRuntimePermission(platform) {
|
|
2674
2816
|
if (platform.OS !== "android") return false;
|
|
@@ -3269,7 +3411,7 @@ var init_paywallHeartbeat = __esm({
|
|
|
3269
3411
|
});
|
|
3270
3412
|
|
|
3271
3413
|
// src/utils/localization.ts
|
|
3272
|
-
import { NativeModules as
|
|
3414
|
+
import { NativeModules as NativeModules4, Platform as Platform9 } from "react-native";
|
|
3273
3415
|
function setCurrentLanguage(language) {
|
|
3274
3416
|
currentLanguage = language;
|
|
3275
3417
|
}
|
|
@@ -3289,11 +3431,11 @@ function getLocalizedString(text) {
|
|
|
3289
3431
|
}
|
|
3290
3432
|
function detectDeviceLanguage() {
|
|
3291
3433
|
try {
|
|
3292
|
-
if (
|
|
3293
|
-
const settings =
|
|
3434
|
+
if (Platform9.OS === "ios") {
|
|
3435
|
+
const settings = NativeModules4.SettingsManager?.settings;
|
|
3294
3436
|
return settings?.AppleLocale ?? settings?.AppleLanguages?.[0] ?? "en-US";
|
|
3295
3437
|
}
|
|
3296
|
-
return
|
|
3438
|
+
return NativeModules4.I18nManager?.localeIdentifier ?? "en-US";
|
|
3297
3439
|
} catch {
|
|
3298
3440
|
return "en-US";
|
|
3299
3441
|
}
|
|
@@ -3464,8 +3606,8 @@ import {
|
|
|
3464
3606
|
findNodeHandle,
|
|
3465
3607
|
Linking as Linking2,
|
|
3466
3608
|
NativeEventEmitter as NativeEventEmitter2,
|
|
3467
|
-
NativeModules as
|
|
3468
|
-
Platform as
|
|
3609
|
+
NativeModules as NativeModules5,
|
|
3610
|
+
Platform as Platform10,
|
|
3469
3611
|
requireNativeComponent,
|
|
3470
3612
|
StyleSheet as StyleSheet2,
|
|
3471
3613
|
UIManager,
|
|
@@ -3485,7 +3627,7 @@ function getNativeWebView() {
|
|
|
3485
3627
|
}
|
|
3486
3628
|
function getWebViewEmitter() {
|
|
3487
3629
|
if (webViewEmitter) return webViewEmitter;
|
|
3488
|
-
const mod =
|
|
3630
|
+
const mod = NativeModules5.PaywalloWebViewModule;
|
|
3489
3631
|
if (!mod) return null;
|
|
3490
3632
|
webViewEmitter = new NativeEventEmitter2(mod);
|
|
3491
3633
|
return webViewEmitter;
|
|
@@ -3578,7 +3720,7 @@ function PaywallWebView({
|
|
|
3578
3720
|
}
|
|
3579
3721
|
}, []);
|
|
3580
3722
|
const injectScript = useCallback((script) => {
|
|
3581
|
-
if (
|
|
3723
|
+
if (Platform10.OS === "android") {
|
|
3582
3724
|
const handle = findNodeHandle(webViewRef.current);
|
|
3583
3725
|
if (handle == null) return;
|
|
3584
3726
|
UIManager.dispatchViewManagerCommand(handle, "injectJavaScript", [script]);
|
|
@@ -3722,7 +3864,7 @@ function PaywallWebView({
|
|
|
3722
3864
|
injectScript(buildPurchaseStateScript(isPurchasing));
|
|
3723
3865
|
}, [isPurchasing, injectScript]);
|
|
3724
3866
|
useEffect2(() => {
|
|
3725
|
-
if (
|
|
3867
|
+
if (Platform10.OS !== "android") return;
|
|
3726
3868
|
const onBackPress = () => {
|
|
3727
3869
|
if (!paywallDataSent.current) return false;
|
|
3728
3870
|
injectScript(buildBackButtonScript());
|
|
@@ -3763,269 +3905,25 @@ var init_PaywallWebView = __esm({
|
|
|
3763
3905
|
}
|
|
3764
3906
|
});
|
|
3765
3907
|
|
|
3766
|
-
// src/domains/iap/PurchaseError.ts
|
|
3767
|
-
function createPurchaseError(code, message) {
|
|
3768
|
-
return new PurchaseError(
|
|
3769
|
-
PURCHASE_ERROR_CODES[code],
|
|
3770
|
-
message ?? DEFAULT_MESSAGES[code] ?? "Unknown purchase error",
|
|
3771
|
-
code === "USER_CANCELLED"
|
|
3772
|
-
);
|
|
3773
|
-
}
|
|
3774
|
-
var PurchaseError, PURCHASE_ERROR_CODES, DEFAULT_MESSAGES;
|
|
3775
|
-
var init_PurchaseError = __esm({
|
|
3776
|
-
"src/domains/iap/PurchaseError.ts"() {
|
|
3777
|
-
"use strict";
|
|
3778
|
-
init_PaywalloError();
|
|
3779
|
-
PurchaseError = class extends PaywalloError {
|
|
3780
|
-
constructor(code, message, userCancelled = false, httpStatus) {
|
|
3781
|
-
super("purchase", code, message);
|
|
3782
|
-
this.name = "PurchaseError";
|
|
3783
|
-
this.userCancelled = userCancelled;
|
|
3784
|
-
this.httpStatus = httpStatus;
|
|
3785
|
-
}
|
|
3786
|
-
};
|
|
3787
|
-
PURCHASE_ERROR_CODES = {
|
|
3788
|
-
NOT_INITIALIZED: "PURCHASE_NOT_INITIALIZED",
|
|
3789
|
-
PRODUCT_NOT_FOUND: "PRODUCT_NOT_FOUND",
|
|
3790
|
-
PURCHASE_FAILED: "PURCHASE_FAILED",
|
|
3791
|
-
RESTORE_FAILED: "RESTORE_FAILED",
|
|
3792
|
-
VALIDATION_FAILED: "VALIDATION_FAILED",
|
|
3793
|
-
USER_CANCELLED: "USER_CANCELLED",
|
|
3794
|
-
NETWORK_ERROR: "PURCHASE_NETWORK_ERROR",
|
|
3795
|
-
STORE_ERROR: "PURCHASE_STORE_ERROR",
|
|
3796
|
-
PENDING_PURCHASE: "PURCHASE_PENDING",
|
|
3797
|
-
DEFERRED_PURCHASE: "PURCHASE_DEFERRED",
|
|
3798
|
-
STORE_NOT_AVAILABLE: "PURCHASE_STORE_NOT_AVAILABLE"
|
|
3799
|
-
};
|
|
3800
|
-
DEFAULT_MESSAGES = {
|
|
3801
|
-
NOT_INITIALIZED: "Purchase controller not initialized. Call init() first.",
|
|
3802
|
-
PRODUCT_NOT_FOUND: "Product not found in store.",
|
|
3803
|
-
PURCHASE_FAILED: "Purchase failed. Please try again.",
|
|
3804
|
-
RESTORE_FAILED: "Failed to restore purchases. Please try again.",
|
|
3805
|
-
VALIDATION_FAILED: "Failed to validate purchase with server.",
|
|
3806
|
-
USER_CANCELLED: "Purchase was cancelled.",
|
|
3807
|
-
NETWORK_ERROR: "Network error. Please check your connection.",
|
|
3808
|
-
STORE_ERROR: "Store error. Please try again later.",
|
|
3809
|
-
PENDING_PURCHASE: "Purchase is pending approval.",
|
|
3810
|
-
DEFERRED_PURCHASE: "Purchase is deferred (e.g., parental approval required).",
|
|
3811
|
-
STORE_NOT_AVAILABLE: "In-app purchases are not available on this device."
|
|
3812
|
-
};
|
|
3813
|
-
}
|
|
3814
|
-
});
|
|
3815
|
-
|
|
3816
|
-
// src/domains/iap/NativeStoreKit.ts
|
|
3817
|
-
var NativeStoreKit_exports = {};
|
|
3818
|
-
__export(NativeStoreKit_exports, {
|
|
3819
|
-
NativeStoreKit: () => NativeStoreKit,
|
|
3820
|
-
nativeStoreKit: () => nativeStoreKit
|
|
3821
|
-
});
|
|
3822
|
-
import { NativeEventEmitter as NativeEventEmitter3, NativeModules as NativeModules7, Platform as Platform10 } from "react-native";
|
|
3823
|
-
function isAvailable3() {
|
|
3824
|
-
return PaywalloStoreKitNative != null;
|
|
3825
|
-
}
|
|
3826
|
-
function mapNativeProduct(native) {
|
|
3827
|
-
const product = {
|
|
3828
|
-
productId: native.productId,
|
|
3829
|
-
title: native.title,
|
|
3830
|
-
description: native.description,
|
|
3831
|
-
price: native.price,
|
|
3832
|
-
priceValue: native.priceValue,
|
|
3833
|
-
currency: native.currency ?? "USD",
|
|
3834
|
-
localizedPrice: native.localizedPrice,
|
|
3835
|
-
type: mapProductType(native.type),
|
|
3836
|
-
subscriptionPeriod: native.subscriptionPeriod,
|
|
3837
|
-
introductoryPrice: native.introductoryPrice,
|
|
3838
|
-
introductoryPriceValue: native.introductoryPriceValue,
|
|
3839
|
-
freeTrialPeriod: native.freeTrialPeriod
|
|
3840
|
-
};
|
|
3841
|
-
if (native.subscriptionPeriod) {
|
|
3842
|
-
const prices = calculatePerPeriodPrices(native.priceValue, native.subscriptionPeriod);
|
|
3843
|
-
product.pricePerMonth = prices.perMonth;
|
|
3844
|
-
product.pricePerWeek = prices.perWeek;
|
|
3845
|
-
product.pricePerDay = prices.perDay;
|
|
3846
|
-
}
|
|
3847
|
-
return product;
|
|
3848
|
-
}
|
|
3849
|
-
function mapProductType(type) {
|
|
3850
|
-
switch (type) {
|
|
3851
|
-
case "subscription":
|
|
3852
|
-
case "autoRenewable":
|
|
3853
|
-
return "subscription";
|
|
3854
|
-
case "consumable":
|
|
3855
|
-
return "consumable";
|
|
3856
|
-
default:
|
|
3857
|
-
return "non_consumable";
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
function calculatePerPeriodPrices(priceValue, period) {
|
|
3861
|
-
const totalDays = periodToDays(period);
|
|
3862
|
-
if (totalDays <= 0) return {};
|
|
3863
|
-
const perDay = priceValue / totalDays;
|
|
3864
|
-
const perWeek = perDay * 7;
|
|
3865
|
-
const perMonth = perDay * 30;
|
|
3866
|
-
return {
|
|
3867
|
-
perDay: perDay.toFixed(2),
|
|
3868
|
-
perWeek: perWeek.toFixed(2),
|
|
3869
|
-
perMonth: perMonth.toFixed(2)
|
|
3870
|
-
};
|
|
3871
|
-
}
|
|
3872
|
-
function periodToDays(period) {
|
|
3873
|
-
const match = period.match(/^P(\d+)([DWMY])$/);
|
|
3874
|
-
if (!match) return 0;
|
|
3875
|
-
const value = parseInt(match[1], 10);
|
|
3876
|
-
switch (match[2]) {
|
|
3877
|
-
case "D":
|
|
3878
|
-
return value;
|
|
3879
|
-
case "W":
|
|
3880
|
-
return value * 7;
|
|
3881
|
-
case "M":
|
|
3882
|
-
return value * 30;
|
|
3883
|
-
case "Y":
|
|
3884
|
-
return value * 365;
|
|
3885
|
-
default:
|
|
3886
|
-
return 0;
|
|
3887
|
-
}
|
|
3888
|
-
}
|
|
3889
|
-
function mapNativePurchase(native) {
|
|
3890
|
-
return {
|
|
3891
|
-
productId: native.productId,
|
|
3892
|
-
transactionId: native.transactionId,
|
|
3893
|
-
transactionDate: native.transactionDate,
|
|
3894
|
-
receipt: native.receipt,
|
|
3895
|
-
platform: Platform10.OS
|
|
3896
|
-
};
|
|
3897
|
-
}
|
|
3898
|
-
function normalizeTransactionUpdate(raw) {
|
|
3899
|
-
if (!raw || typeof raw !== "object") return null;
|
|
3900
|
-
const r = raw;
|
|
3901
|
-
const type = r.type;
|
|
3902
|
-
if (type !== "renewed" && type !== "refunded" && type !== "canceled") return null;
|
|
3903
|
-
const transactionId = typeof r.transactionId === "string" ? r.transactionId : null;
|
|
3904
|
-
const productId = typeof r.productId === "string" ? r.productId : null;
|
|
3905
|
-
if (!transactionId) return null;
|
|
3906
|
-
const update = {
|
|
3907
|
-
type,
|
|
3908
|
-
transactionId,
|
|
3909
|
-
productId: productId ?? ""
|
|
3910
|
-
};
|
|
3911
|
-
if (typeof r.amount === "number") update.amount = r.amount;
|
|
3912
|
-
if (typeof r.currency === "string") update.currency = r.currency;
|
|
3913
|
-
return update;
|
|
3914
|
-
}
|
|
3915
|
-
var TRANSACTION_UPDATE_EVENT, PaywalloStoreKitNative, nativeStoreKit, NativeStoreKit;
|
|
3916
|
-
var init_NativeStoreKit = __esm({
|
|
3917
|
-
"src/domains/iap/NativeStoreKit.ts"() {
|
|
3918
|
-
"use strict";
|
|
3919
|
-
init_PaywalloClient();
|
|
3920
|
-
init_uuid();
|
|
3921
|
-
init_IdentityManager();
|
|
3922
|
-
init_PurchaseError();
|
|
3923
|
-
TRANSACTION_UPDATE_EVENT = "PaywalloTransactionUpdate";
|
|
3924
|
-
PaywalloStoreKitNative = NativeModules7.PaywalloStoreKit ?? null;
|
|
3925
|
-
nativeStoreKit = {
|
|
3926
|
-
isAvailable: isAvailable3,
|
|
3927
|
-
async getProducts(productIds) {
|
|
3928
|
-
if (!PaywalloStoreKitNative) {
|
|
3929
|
-
return [];
|
|
3930
|
-
}
|
|
3931
|
-
const nativeProducts = await PaywalloStoreKitNative.getProducts(productIds);
|
|
3932
|
-
return nativeProducts.map(mapNativeProduct);
|
|
3933
|
-
},
|
|
3934
|
-
async purchase(productId) {
|
|
3935
|
-
if (!PaywalloStoreKitNative) {
|
|
3936
|
-
throw new PurchaseError(
|
|
3937
|
-
PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE,
|
|
3938
|
-
"StoreKit native module not available"
|
|
3939
|
-
);
|
|
3940
|
-
}
|
|
3941
|
-
const distinctId = identityManager.getDistinctId();
|
|
3942
|
-
const rawUuid = distinctId?.startsWith("$paywallo_anon:") ? distinctId.slice("$paywallo_anon:".length) : distinctId;
|
|
3943
|
-
const appAccountToken = isValidUUIDv4(rawUuid) ? rawUuid : null;
|
|
3944
|
-
if (distinctId && appAccountToken === null) {
|
|
3945
|
-
if (PaywalloClient.getConfig()?.debug) console.log("[Paywallo] distinctId is not a valid UUID v4 \u2014 passing null to appAccountToken:", distinctId);
|
|
3946
|
-
}
|
|
3947
|
-
try {
|
|
3948
|
-
const result = await PaywalloStoreKitNative.purchase(productId, appAccountToken);
|
|
3949
|
-
if (!result || result.pending) {
|
|
3950
|
-
return null;
|
|
3951
|
-
}
|
|
3952
|
-
return mapNativePurchase(result);
|
|
3953
|
-
} catch (err) {
|
|
3954
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
3955
|
-
if (message.toLowerCase().includes("cancel")) {
|
|
3956
|
-
throw new PurchaseError(PURCHASE_ERROR_CODES.USER_CANCELLED, message, true);
|
|
3957
|
-
}
|
|
3958
|
-
throw new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, message);
|
|
3959
|
-
}
|
|
3960
|
-
},
|
|
3961
|
-
async finishTransaction(transactionId) {
|
|
3962
|
-
if (!PaywalloStoreKitNative) return;
|
|
3963
|
-
try {
|
|
3964
|
-
await PaywalloStoreKitNative.finishTransaction(transactionId);
|
|
3965
|
-
} catch (err) {
|
|
3966
|
-
console.error("[Paywallo] finishTransaction native error", err);
|
|
3967
|
-
}
|
|
3968
|
-
},
|
|
3969
|
-
async getActiveTransactions() {
|
|
3970
|
-
if (!PaywalloStoreKitNative) return [];
|
|
3971
|
-
try {
|
|
3972
|
-
const results = await PaywalloStoreKitNative.getActiveTransactions();
|
|
3973
|
-
return results.map(mapNativePurchase);
|
|
3974
|
-
} catch (err) {
|
|
3975
|
-
console.error("[Paywallo] getActiveTransactions failed", err);
|
|
3976
|
-
return [];
|
|
3977
|
-
}
|
|
3978
|
-
},
|
|
3979
|
-
/**
|
|
3980
|
-
* Subscribes to native transaction update events (renewals, refunds,
|
|
3981
|
-
* cancellations) from StoreKit 2 (`Transaction.updates`) on iOS or
|
|
3982
|
-
* `PurchasesUpdatedListener` + refund diff on Android.
|
|
3983
|
-
*
|
|
3984
|
-
* Returns a subscription with a `remove()` method. The caller is
|
|
3985
|
-
* responsible for cleanup (typically on `Paywallo.reset()`).
|
|
3986
|
-
*
|
|
3987
|
-
* Returns `null` when the native module isn't available (non-mobile env,
|
|
3988
|
-
* native module not linked) — callers should treat null as a no-op.
|
|
3989
|
-
*/
|
|
3990
|
-
subscribeToTransactionUpdates(listener) {
|
|
3991
|
-
if (!PaywalloStoreKitNative) return null;
|
|
3992
|
-
try {
|
|
3993
|
-
const EmitterCtor = NativeEventEmitter3;
|
|
3994
|
-
const emitter = new EmitterCtor(PaywalloStoreKitNative);
|
|
3995
|
-
const sub = emitter.addListener(TRANSACTION_UPDATE_EVENT, (payload) => {
|
|
3996
|
-
const update = normalizeTransactionUpdate(payload);
|
|
3997
|
-
if (update) listener(update);
|
|
3998
|
-
});
|
|
3999
|
-
return { remove: () => sub.remove() };
|
|
4000
|
-
} catch (err) {
|
|
4001
|
-
if (PaywalloClient.getConfig()?.debug) console.log("[Paywallo] subscribeToTransactionUpdates failed", err);
|
|
4002
|
-
return null;
|
|
4003
|
-
}
|
|
4004
|
-
}
|
|
4005
|
-
};
|
|
4006
|
-
NativeStoreKit = nativeStoreKit;
|
|
4007
|
-
}
|
|
4008
|
-
});
|
|
4009
|
-
|
|
4010
3908
|
// src/domains/iap/IAPTransactionEmitter.ts
|
|
4011
3909
|
var IAPTransactionEmitter;
|
|
4012
3910
|
var init_IAPTransactionEmitter = __esm({
|
|
4013
3911
|
"src/domains/iap/IAPTransactionEmitter.ts"() {
|
|
4014
3912
|
"use strict";
|
|
4015
3913
|
init_PaywalloClient();
|
|
4016
|
-
init_NativeStoreKit();
|
|
4017
3914
|
IAPTransactionEmitter = class {
|
|
4018
3915
|
constructor(getProductFromCache, getApiClientFn, getDebug) {
|
|
4019
3916
|
this.getProductFromCache = getProductFromCache;
|
|
4020
3917
|
this.getApiClientFn = getApiClientFn;
|
|
4021
3918
|
this.getDebug = getDebug;
|
|
4022
|
-
this.transactionUpdateSubscription = null;
|
|
4023
3919
|
}
|
|
4024
3920
|
/**
|
|
4025
|
-
* Emits `
|
|
4026
|
-
*
|
|
3921
|
+
* Emits `checkout_started` quando o usuário inicia a compra (toca em comprar),
|
|
3922
|
+
* antes do StoreKit/Billing abrir — conta mesmo que a sheet nativa seja cancelada.
|
|
3923
|
+
* Vira InitiateCheckout no Meta/TikTok. Fire-and-forget — uma falha de tracking
|
|
3924
|
+
* nunca pode travar a compra.
|
|
4027
3925
|
*/
|
|
4028
|
-
async
|
|
3926
|
+
async emitCheckoutStarted(productId) {
|
|
4029
3927
|
try {
|
|
4030
3928
|
const apiClient = this.getApiClientFn();
|
|
4031
3929
|
if (!apiClient) return;
|
|
@@ -4033,40 +3931,9 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
4033
3931
|
if (!distinctId) return;
|
|
4034
3932
|
const product = this.getProductFromCache(productId);
|
|
4035
3933
|
const properties = {
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
};
|
|
4040
|
-
if (product?.priceValue !== void 0 && product.priceValue > 0) {
|
|
4041
|
-
properties.amount = product.priceValue;
|
|
4042
|
-
}
|
|
4043
|
-
if (product?.currency) {
|
|
4044
|
-
properties.currency = product.currency;
|
|
4045
|
-
}
|
|
4046
|
-
if (options?.paywallId) properties.paywall_id = options.paywallId;
|
|
4047
|
-
if (options?.variantId) properties.variant_id = options.variantId;
|
|
4048
|
-
await apiClient.trackEvent("transaction", distinctId, properties, void 0, { priority: "critical" });
|
|
4049
|
-
} catch (err) {
|
|
4050
|
-
if (this.getDebug()) console.log("[Paywallo PURCHASE] transaction event emission failed", err);
|
|
4051
|
-
}
|
|
4052
|
-
}
|
|
4053
|
-
/**
|
|
4054
|
-
* Emits `checkout_started` quando o usuário inicia a compra (toca em comprar),
|
|
4055
|
-
* antes do StoreKit/Billing abrir — conta mesmo que a sheet nativa seja cancelada.
|
|
4056
|
-
* Vira InitiateCheckout no Meta/TikTok. Fire-and-forget — uma falha de tracking
|
|
4057
|
-
* nunca pode travar a compra.
|
|
4058
|
-
*/
|
|
4059
|
-
async emitCheckoutStarted(productId) {
|
|
4060
|
-
try {
|
|
4061
|
-
const apiClient = this.getApiClientFn();
|
|
4062
|
-
if (!apiClient) return;
|
|
4063
|
-
const distinctId = PaywalloClient.getDistinctId();
|
|
4064
|
-
if (!distinctId) return;
|
|
4065
|
-
const product = this.getProductFromCache(productId);
|
|
4066
|
-
const properties = {
|
|
4067
|
-
product_id: productId,
|
|
4068
|
-
amount: product?.priceValue ?? 0,
|
|
4069
|
-
currency: product?.currency ?? "USD"
|
|
3934
|
+
product_id: productId,
|
|
3935
|
+
amount: product?.priceValue ?? 0,
|
|
3936
|
+
currency: product?.currency ?? "USD"
|
|
4070
3937
|
};
|
|
4071
3938
|
await apiClient.trackEvent("checkout_started", distinctId, properties, void 0, {
|
|
4072
3939
|
priority: "critical"
|
|
@@ -4077,93 +3944,20 @@ var init_IAPTransactionEmitter = __esm({
|
|
|
4077
3944
|
}
|
|
4078
3945
|
}
|
|
4079
3946
|
/**
|
|
4080
|
-
*
|
|
4081
|
-
*
|
|
4082
|
-
*/
|
|
4083
|
-
async emitTransactionUpdate(update) {
|
|
4084
|
-
try {
|
|
4085
|
-
const apiClient = this.getApiClientFn() ?? PaywalloClient.getApiClient();
|
|
4086
|
-
if (!apiClient) {
|
|
4087
|
-
if (this.getDebug()) console.log("[Paywallo IAP] transaction update dropped (no apiClient)", update.type);
|
|
4088
|
-
return;
|
|
4089
|
-
}
|
|
4090
|
-
const distinctId = PaywalloClient.getDistinctId();
|
|
4091
|
-
if (!distinctId) {
|
|
4092
|
-
if (this.getDebug()) console.log("[Paywallo IAP] transaction update dropped (no distinctId)", update.type);
|
|
4093
|
-
return;
|
|
4094
|
-
}
|
|
4095
|
-
const properties = {
|
|
4096
|
-
type: update.type,
|
|
4097
|
-
tx_id: update.transactionId,
|
|
4098
|
-
product_id: update.productId
|
|
4099
|
-
};
|
|
4100
|
-
if (update.type !== "canceled") {
|
|
4101
|
-
const cached2 = this.getProductFromCache(update.productId);
|
|
4102
|
-
const amount = update.amount ?? cached2?.priceValue;
|
|
4103
|
-
const currency = update.currency ?? cached2?.currency;
|
|
4104
|
-
if (typeof amount === "number" && amount > 0) properties.amount = amount;
|
|
4105
|
-
if (currency) properties.currency = currency;
|
|
4106
|
-
}
|
|
4107
|
-
await apiClient.trackEvent("transaction", distinctId, properties, void 0, { priority: "critical" });
|
|
4108
|
-
if (this.getDebug()) console.log(`[Paywallo IAP] emitted transaction {${update.type}}`, update.transactionId);
|
|
4109
|
-
} catch (err) {
|
|
4110
|
-
if (this.getDebug()) console.log("[Paywallo IAP] transaction update emission failed", err);
|
|
4111
|
-
}
|
|
4112
|
-
}
|
|
4113
|
-
/**
|
|
4114
|
-
* Starts listening to native Transaction.updates. Idempotent.
|
|
3947
|
+
* No-op. Native transaction update listener removed — sale events are sourced
|
|
3948
|
+
* exclusively from server-side webhooks (Apple/Google/Superwall/RevenueCat).
|
|
4115
3949
|
*/
|
|
4116
3950
|
startListener() {
|
|
4117
|
-
if (this.transactionUpdateSubscription) return;
|
|
4118
|
-
this.transactionUpdateSubscription = nativeStoreKit.subscribeToTransactionUpdates(
|
|
4119
|
-
(update) => {
|
|
4120
|
-
void this.emitTransactionUpdate(update);
|
|
4121
|
-
}
|
|
4122
|
-
);
|
|
4123
|
-
if (this.getDebug() && this.transactionUpdateSubscription) {
|
|
4124
|
-
console.log("[Paywallo IAP] transaction update listener started");
|
|
4125
|
-
}
|
|
4126
3951
|
}
|
|
4127
3952
|
/**
|
|
4128
|
-
*
|
|
3953
|
+
* No-op. See startListener.
|
|
4129
3954
|
*/
|
|
4130
3955
|
stopListener() {
|
|
4131
|
-
if (!this.transactionUpdateSubscription) return;
|
|
4132
|
-
try {
|
|
4133
|
-
this.transactionUpdateSubscription.remove();
|
|
4134
|
-
} catch (err) {
|
|
4135
|
-
if (this.getDebug()) console.log("[Paywallo IAP] transaction listener removal failed", err);
|
|
4136
|
-
}
|
|
4137
|
-
this.transactionUpdateSubscription = null;
|
|
4138
|
-
if (this.getDebug()) console.log("[Paywallo IAP] transaction update listener stopped");
|
|
4139
3956
|
}
|
|
4140
3957
|
};
|
|
4141
3958
|
}
|
|
4142
3959
|
});
|
|
4143
3960
|
|
|
4144
|
-
// src/errors/ClientError.ts
|
|
4145
|
-
var ClientError, CLIENT_ERROR_CODES;
|
|
4146
|
-
var init_ClientError = __esm({
|
|
4147
|
-
"src/errors/ClientError.ts"() {
|
|
4148
|
-
"use strict";
|
|
4149
|
-
init_PaywalloError();
|
|
4150
|
-
ClientError = class extends PaywalloError {
|
|
4151
|
-
constructor(code, message) {
|
|
4152
|
-
super("client", code, message);
|
|
4153
|
-
this.name = "ClientError";
|
|
4154
|
-
}
|
|
4155
|
-
};
|
|
4156
|
-
CLIENT_ERROR_CODES = {
|
|
4157
|
-
NOT_INITIALIZED: "CLIENT_NOT_INITIALIZED",
|
|
4158
|
-
MISSING_APP_KEY: "CLIENT_MISSING_APP_KEY",
|
|
4159
|
-
INVALID_EVENT_NAME: "CLIENT_INVALID_EVENT_NAME",
|
|
4160
|
-
PROVIDER_MISSING: "CLIENT_PROVIDER_MISSING",
|
|
4161
|
-
INSECURE_REQUEST: "CLIENT_INSECURE_REQUEST",
|
|
4162
|
-
UNKNOWN: "CLIENT_UNKNOWN"
|
|
4163
|
-
};
|
|
4164
|
-
}
|
|
4165
|
-
});
|
|
4166
|
-
|
|
4167
3961
|
// src/core/queue/deduplication.ts
|
|
4168
3962
|
function normalizeForComparison(obj) {
|
|
4169
3963
|
if (obj === null || obj === void 0) {
|
|
@@ -5047,6 +4841,56 @@ var init_queue = __esm({
|
|
|
5047
4841
|
}
|
|
5048
4842
|
});
|
|
5049
4843
|
|
|
4844
|
+
// src/domains/iap/PurchaseError.ts
|
|
4845
|
+
function createPurchaseError(code, message) {
|
|
4846
|
+
return new PurchaseError(
|
|
4847
|
+
PURCHASE_ERROR_CODES[code],
|
|
4848
|
+
message ?? DEFAULT_MESSAGES[code] ?? "Unknown purchase error",
|
|
4849
|
+
code === "USER_CANCELLED"
|
|
4850
|
+
);
|
|
4851
|
+
}
|
|
4852
|
+
var PurchaseError, PURCHASE_ERROR_CODES, DEFAULT_MESSAGES;
|
|
4853
|
+
var init_PurchaseError = __esm({
|
|
4854
|
+
"src/domains/iap/PurchaseError.ts"() {
|
|
4855
|
+
"use strict";
|
|
4856
|
+
init_PaywalloError();
|
|
4857
|
+
PurchaseError = class extends PaywalloError {
|
|
4858
|
+
constructor(code, message, userCancelled = false, httpStatus) {
|
|
4859
|
+
super("purchase", code, message);
|
|
4860
|
+
this.name = "PurchaseError";
|
|
4861
|
+
this.userCancelled = userCancelled;
|
|
4862
|
+
this.httpStatus = httpStatus;
|
|
4863
|
+
}
|
|
4864
|
+
};
|
|
4865
|
+
PURCHASE_ERROR_CODES = {
|
|
4866
|
+
NOT_INITIALIZED: "PURCHASE_NOT_INITIALIZED",
|
|
4867
|
+
PRODUCT_NOT_FOUND: "PRODUCT_NOT_FOUND",
|
|
4868
|
+
PURCHASE_FAILED: "PURCHASE_FAILED",
|
|
4869
|
+
RESTORE_FAILED: "RESTORE_FAILED",
|
|
4870
|
+
VALIDATION_FAILED: "VALIDATION_FAILED",
|
|
4871
|
+
USER_CANCELLED: "USER_CANCELLED",
|
|
4872
|
+
NETWORK_ERROR: "PURCHASE_NETWORK_ERROR",
|
|
4873
|
+
STORE_ERROR: "PURCHASE_STORE_ERROR",
|
|
4874
|
+
PENDING_PURCHASE: "PURCHASE_PENDING",
|
|
4875
|
+
DEFERRED_PURCHASE: "PURCHASE_DEFERRED",
|
|
4876
|
+
STORE_NOT_AVAILABLE: "PURCHASE_STORE_NOT_AVAILABLE"
|
|
4877
|
+
};
|
|
4878
|
+
DEFAULT_MESSAGES = {
|
|
4879
|
+
NOT_INITIALIZED: "Purchase controller not initialized. Call init() first.",
|
|
4880
|
+
PRODUCT_NOT_FOUND: "Product not found in store.",
|
|
4881
|
+
PURCHASE_FAILED: "Purchase failed. Please try again.",
|
|
4882
|
+
RESTORE_FAILED: "Failed to restore purchases. Please try again.",
|
|
4883
|
+
VALIDATION_FAILED: "Failed to validate purchase with server.",
|
|
4884
|
+
USER_CANCELLED: "Purchase was cancelled.",
|
|
4885
|
+
NETWORK_ERROR: "Network error. Please check your connection.",
|
|
4886
|
+
STORE_ERROR: "Store error. Please try again later.",
|
|
4887
|
+
PENDING_PURCHASE: "Purchase is pending approval.",
|
|
4888
|
+
DEFERRED_PURCHASE: "Purchase is deferred (e.g., parental approval required).",
|
|
4889
|
+
STORE_NOT_AVAILABLE: "In-app purchases are not available on this device."
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
});
|
|
4893
|
+
|
|
5050
4894
|
// src/domains/iap/IAPValidator.ts
|
|
5051
4895
|
import { Platform as Platform11 } from "react-native";
|
|
5052
4896
|
var IAPValidator;
|
|
@@ -5145,8 +4989,202 @@ var init_IAPValidator = __esm({
|
|
|
5145
4989
|
}
|
|
5146
4990
|
});
|
|
5147
4991
|
|
|
4992
|
+
// src/domains/iap/NativeStoreKit.ts
|
|
4993
|
+
var NativeStoreKit_exports = {};
|
|
4994
|
+
__export(NativeStoreKit_exports, {
|
|
4995
|
+
NativeStoreKit: () => NativeStoreKit,
|
|
4996
|
+
nativeStoreKit: () => nativeStoreKit
|
|
4997
|
+
});
|
|
4998
|
+
import { NativeEventEmitter as NativeEventEmitter3, NativeModules as NativeModules6, Platform as Platform12 } from "react-native";
|
|
4999
|
+
function isAvailable3() {
|
|
5000
|
+
return PaywalloStoreKitNative != null;
|
|
5001
|
+
}
|
|
5002
|
+
function mapNativeProduct(native) {
|
|
5003
|
+
const product = {
|
|
5004
|
+
productId: native.productId,
|
|
5005
|
+
title: native.title,
|
|
5006
|
+
description: native.description,
|
|
5007
|
+
price: native.price,
|
|
5008
|
+
priceValue: native.priceValue,
|
|
5009
|
+
currency: native.currency ?? "USD",
|
|
5010
|
+
localizedPrice: native.localizedPrice,
|
|
5011
|
+
type: mapProductType(native.type),
|
|
5012
|
+
subscriptionPeriod: native.subscriptionPeriod,
|
|
5013
|
+
introductoryPrice: native.introductoryPrice,
|
|
5014
|
+
introductoryPriceValue: native.introductoryPriceValue,
|
|
5015
|
+
freeTrialPeriod: native.freeTrialPeriod
|
|
5016
|
+
};
|
|
5017
|
+
if (native.subscriptionPeriod) {
|
|
5018
|
+
const prices = calculatePerPeriodPrices(native.priceValue, native.subscriptionPeriod);
|
|
5019
|
+
product.pricePerMonth = prices.perMonth;
|
|
5020
|
+
product.pricePerWeek = prices.perWeek;
|
|
5021
|
+
product.pricePerDay = prices.perDay;
|
|
5022
|
+
}
|
|
5023
|
+
return product;
|
|
5024
|
+
}
|
|
5025
|
+
function mapProductType(type) {
|
|
5026
|
+
switch (type) {
|
|
5027
|
+
case "subscription":
|
|
5028
|
+
case "autoRenewable":
|
|
5029
|
+
return "subscription";
|
|
5030
|
+
case "consumable":
|
|
5031
|
+
return "consumable";
|
|
5032
|
+
default:
|
|
5033
|
+
return "non_consumable";
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
function calculatePerPeriodPrices(priceValue, period) {
|
|
5037
|
+
const totalDays = periodToDays(period);
|
|
5038
|
+
if (totalDays <= 0) return {};
|
|
5039
|
+
const perDay = priceValue / totalDays;
|
|
5040
|
+
const perWeek = perDay * 7;
|
|
5041
|
+
const perMonth = perDay * 30;
|
|
5042
|
+
return {
|
|
5043
|
+
perDay: perDay.toFixed(2),
|
|
5044
|
+
perWeek: perWeek.toFixed(2),
|
|
5045
|
+
perMonth: perMonth.toFixed(2)
|
|
5046
|
+
};
|
|
5047
|
+
}
|
|
5048
|
+
function periodToDays(period) {
|
|
5049
|
+
const match = period.match(/^P(\d+)([DWMY])$/);
|
|
5050
|
+
if (!match) return 0;
|
|
5051
|
+
const value = parseInt(match[1], 10);
|
|
5052
|
+
switch (match[2]) {
|
|
5053
|
+
case "D":
|
|
5054
|
+
return value;
|
|
5055
|
+
case "W":
|
|
5056
|
+
return value * 7;
|
|
5057
|
+
case "M":
|
|
5058
|
+
return value * 30;
|
|
5059
|
+
case "Y":
|
|
5060
|
+
return value * 365;
|
|
5061
|
+
default:
|
|
5062
|
+
return 0;
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
function mapNativePurchase(native) {
|
|
5066
|
+
return {
|
|
5067
|
+
productId: native.productId,
|
|
5068
|
+
transactionId: native.transactionId,
|
|
5069
|
+
transactionDate: native.transactionDate,
|
|
5070
|
+
receipt: native.receipt,
|
|
5071
|
+
platform: Platform12.OS
|
|
5072
|
+
};
|
|
5073
|
+
}
|
|
5074
|
+
function normalizeTransactionUpdate(raw) {
|
|
5075
|
+
if (!raw || typeof raw !== "object") return null;
|
|
5076
|
+
const r = raw;
|
|
5077
|
+
const type = r.type;
|
|
5078
|
+
if (type !== "renewed" && type !== "refunded" && type !== "canceled") return null;
|
|
5079
|
+
const transactionId = typeof r.transactionId === "string" ? r.transactionId : null;
|
|
5080
|
+
const productId = typeof r.productId === "string" ? r.productId : null;
|
|
5081
|
+
if (!transactionId) return null;
|
|
5082
|
+
const update = {
|
|
5083
|
+
type,
|
|
5084
|
+
transactionId,
|
|
5085
|
+
productId: productId ?? ""
|
|
5086
|
+
};
|
|
5087
|
+
if (typeof r.amount === "number") update.amount = r.amount;
|
|
5088
|
+
if (typeof r.currency === "string") update.currency = r.currency;
|
|
5089
|
+
return update;
|
|
5090
|
+
}
|
|
5091
|
+
var TRANSACTION_UPDATE_EVENT, PaywalloStoreKitNative, nativeStoreKit, NativeStoreKit;
|
|
5092
|
+
var init_NativeStoreKit = __esm({
|
|
5093
|
+
"src/domains/iap/NativeStoreKit.ts"() {
|
|
5094
|
+
"use strict";
|
|
5095
|
+
init_PaywalloClient();
|
|
5096
|
+
init_uuid();
|
|
5097
|
+
init_IdentityManager();
|
|
5098
|
+
init_PurchaseError();
|
|
5099
|
+
TRANSACTION_UPDATE_EVENT = "PaywalloTransactionUpdate";
|
|
5100
|
+
PaywalloStoreKitNative = NativeModules6.PaywalloStoreKit ?? null;
|
|
5101
|
+
nativeStoreKit = {
|
|
5102
|
+
isAvailable: isAvailable3,
|
|
5103
|
+
async getProducts(productIds) {
|
|
5104
|
+
if (!PaywalloStoreKitNative) {
|
|
5105
|
+
return [];
|
|
5106
|
+
}
|
|
5107
|
+
const nativeProducts = await PaywalloStoreKitNative.getProducts(productIds);
|
|
5108
|
+
return nativeProducts.map(mapNativeProduct);
|
|
5109
|
+
},
|
|
5110
|
+
async purchase(productId) {
|
|
5111
|
+
if (!PaywalloStoreKitNative) {
|
|
5112
|
+
throw new PurchaseError(
|
|
5113
|
+
PURCHASE_ERROR_CODES.STORE_NOT_AVAILABLE,
|
|
5114
|
+
"StoreKit native module not available"
|
|
5115
|
+
);
|
|
5116
|
+
}
|
|
5117
|
+
const distinctId = identityManager.getDistinctId();
|
|
5118
|
+
const rawUuid = distinctId?.startsWith("$paywallo_anon:") ? distinctId.slice("$paywallo_anon:".length) : distinctId;
|
|
5119
|
+
const appAccountToken = isValidUUIDv4(rawUuid) ? rawUuid : null;
|
|
5120
|
+
if (distinctId && appAccountToken === null) {
|
|
5121
|
+
if (PaywalloClient.getConfig()?.debug) console.log("[Paywallo] distinctId is not a valid UUID v4 \u2014 passing null to appAccountToken:", distinctId);
|
|
5122
|
+
}
|
|
5123
|
+
try {
|
|
5124
|
+
const result = await PaywalloStoreKitNative.purchase(productId, appAccountToken);
|
|
5125
|
+
if (!result || result.pending) {
|
|
5126
|
+
return null;
|
|
5127
|
+
}
|
|
5128
|
+
return mapNativePurchase(result);
|
|
5129
|
+
} catch (err) {
|
|
5130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5131
|
+
if (message.toLowerCase().includes("cancel")) {
|
|
5132
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.USER_CANCELLED, message, true);
|
|
5133
|
+
}
|
|
5134
|
+
throw new PurchaseError(PURCHASE_ERROR_CODES.PURCHASE_FAILED, message);
|
|
5135
|
+
}
|
|
5136
|
+
},
|
|
5137
|
+
async finishTransaction(transactionId) {
|
|
5138
|
+
if (!PaywalloStoreKitNative) return;
|
|
5139
|
+
try {
|
|
5140
|
+
await PaywalloStoreKitNative.finishTransaction(transactionId);
|
|
5141
|
+
} catch (err) {
|
|
5142
|
+
console.error("[Paywallo] finishTransaction native error", err);
|
|
5143
|
+
}
|
|
5144
|
+
},
|
|
5145
|
+
async getActiveTransactions() {
|
|
5146
|
+
if (!PaywalloStoreKitNative) return [];
|
|
5147
|
+
try {
|
|
5148
|
+
const results = await PaywalloStoreKitNative.getActiveTransactions();
|
|
5149
|
+
return results.map(mapNativePurchase);
|
|
5150
|
+
} catch (err) {
|
|
5151
|
+
console.error("[Paywallo] getActiveTransactions failed", err);
|
|
5152
|
+
return [];
|
|
5153
|
+
}
|
|
5154
|
+
},
|
|
5155
|
+
/**
|
|
5156
|
+
* Subscribes to native transaction update events (renewals, refunds,
|
|
5157
|
+
* cancellations) from StoreKit 2 (`Transaction.updates`) on iOS or
|
|
5158
|
+
* `PurchasesUpdatedListener` + refund diff on Android.
|
|
5159
|
+
*
|
|
5160
|
+
* Returns a subscription with a `remove()` method. The caller is
|
|
5161
|
+
* responsible for cleanup (typically on `Paywallo.reset()`).
|
|
5162
|
+
*
|
|
5163
|
+
* Returns `null` when the native module isn't available (non-mobile env,
|
|
5164
|
+
* native module not linked) — callers should treat null as a no-op.
|
|
5165
|
+
*/
|
|
5166
|
+
subscribeToTransactionUpdates(listener) {
|
|
5167
|
+
if (!PaywalloStoreKitNative) return null;
|
|
5168
|
+
try {
|
|
5169
|
+
const EmitterCtor = NativeEventEmitter3;
|
|
5170
|
+
const emitter = new EmitterCtor(PaywalloStoreKitNative);
|
|
5171
|
+
const sub = emitter.addListener(TRANSACTION_UPDATE_EVENT, (payload) => {
|
|
5172
|
+
const update = normalizeTransactionUpdate(payload);
|
|
5173
|
+
if (update) listener(update);
|
|
5174
|
+
});
|
|
5175
|
+
return { remove: () => sub.remove() };
|
|
5176
|
+
} catch (err) {
|
|
5177
|
+
if (PaywalloClient.getConfig()?.debug) console.log("[Paywallo] subscribeToTransactionUpdates failed", err);
|
|
5178
|
+
return null;
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
};
|
|
5182
|
+
NativeStoreKit = nativeStoreKit;
|
|
5183
|
+
}
|
|
5184
|
+
});
|
|
5185
|
+
|
|
5148
5186
|
// src/domains/iap/IAPService.ts
|
|
5149
|
-
import { Platform as
|
|
5187
|
+
import { Platform as Platform13 } from "react-native";
|
|
5150
5188
|
function getIAPService() {
|
|
5151
5189
|
if (!_instance) {
|
|
5152
5190
|
_instance = new IAPService();
|
|
@@ -5245,8 +5283,8 @@ var init_IAPService = __esm({
|
|
|
5245
5283
|
stopTransactionListener() {
|
|
5246
5284
|
this.emitter.stopListener();
|
|
5247
5285
|
}
|
|
5248
|
-
|
|
5249
|
-
|
|
5286
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5287
|
+
async emitTransactionUpdate(_update) {
|
|
5250
5288
|
}
|
|
5251
5289
|
async purchase(productId, options) {
|
|
5252
5290
|
if (!nativeStoreKit.isAvailable()) {
|
|
@@ -5275,10 +5313,6 @@ var init_IAPService = __esm({
|
|
|
5275
5313
|
if (this.debug) console.log(`[Paywallo PURCHASE] ${productId} server validated`);
|
|
5276
5314
|
await this.finishTransaction(purchase.transactionId);
|
|
5277
5315
|
if (this.debug) console.log(`[Paywallo PURCHASE] ${productId} finished`);
|
|
5278
|
-
await this.emitter.emitTransactionCompleted(purchase, productId, {
|
|
5279
|
-
paywallId: options?.paywallId,
|
|
5280
|
-
variantId: options?.variantId
|
|
5281
|
-
});
|
|
5282
5316
|
}).catch(async (err) => {
|
|
5283
5317
|
const kind = this.validator.classifyValidationError(err);
|
|
5284
5318
|
if (kind === "server4xx") {
|
|
@@ -5307,7 +5341,7 @@ var init_IAPService = __esm({
|
|
|
5307
5341
|
const transactions = await nativeStoreKit.getActiveTransactions();
|
|
5308
5342
|
const apiClient = this.getApiClient();
|
|
5309
5343
|
const distinctId = PaywalloClient.getDistinctId();
|
|
5310
|
-
const platform =
|
|
5344
|
+
const platform = Platform13.OS;
|
|
5311
5345
|
const results = await Promise.allSettled(
|
|
5312
5346
|
transactions.map((tx) => {
|
|
5313
5347
|
const product = this.productsCache.get(tx.productId);
|
|
@@ -6374,8 +6408,145 @@ var init_plan = __esm({
|
|
|
6374
6408
|
var init_session = __esm({
|
|
6375
6409
|
"src/domains/session/index.ts"() {
|
|
6376
6410
|
"use strict";
|
|
6377
|
-
init_SessionError();
|
|
6378
|
-
init_SessionManager();
|
|
6411
|
+
init_SessionError();
|
|
6412
|
+
init_SessionManager();
|
|
6413
|
+
}
|
|
6414
|
+
});
|
|
6415
|
+
|
|
6416
|
+
// src/domains/onboarding/OnboardingError.ts
|
|
6417
|
+
var OnboardingError, ONBOARDING_ERROR_CODES;
|
|
6418
|
+
var init_OnboardingError = __esm({
|
|
6419
|
+
"src/domains/onboarding/OnboardingError.ts"() {
|
|
6420
|
+
"use strict";
|
|
6421
|
+
init_PaywalloError();
|
|
6422
|
+
OnboardingError = class extends PaywalloError {
|
|
6423
|
+
constructor(code, message) {
|
|
6424
|
+
super("onboarding", code, message);
|
|
6425
|
+
this.name = "OnboardingError";
|
|
6426
|
+
}
|
|
6427
|
+
};
|
|
6428
|
+
ONBOARDING_ERROR_CODES = {
|
|
6429
|
+
NOT_INITIALIZED: "ONBOARDING_NOT_INITIALIZED",
|
|
6430
|
+
INVALID_STEP_NAME: "ONBOARDING_INVALID_STEP_NAME"
|
|
6431
|
+
};
|
|
6432
|
+
}
|
|
6433
|
+
});
|
|
6434
|
+
|
|
6435
|
+
// src/domains/onboarding/OnboardingManager.ts
|
|
6436
|
+
var OnboardingManager, onboardingManager;
|
|
6437
|
+
var init_OnboardingManager = __esm({
|
|
6438
|
+
"src/domains/onboarding/OnboardingManager.ts"() {
|
|
6439
|
+
"use strict";
|
|
6440
|
+
init_OnboardingError();
|
|
6441
|
+
OnboardingManager = class {
|
|
6442
|
+
constructor() {
|
|
6443
|
+
this.pipeline = null;
|
|
6444
|
+
this.debug = false;
|
|
6445
|
+
this.lastStep = null;
|
|
6446
|
+
this.finished = false;
|
|
6447
|
+
}
|
|
6448
|
+
/**
|
|
6449
|
+
* Injects runtime dependencies. Called by PaywalloClient during init.
|
|
6450
|
+
*/
|
|
6451
|
+
injectDeps(config) {
|
|
6452
|
+
this.pipeline = config.pipeline;
|
|
6453
|
+
this.debug = config.debug ?? false;
|
|
6454
|
+
}
|
|
6455
|
+
/**
|
|
6456
|
+
* Tracks an onboarding step view.
|
|
6457
|
+
* Saves the step name internally for implicit drop detection on the backend.
|
|
6458
|
+
*
|
|
6459
|
+
* @param stepName - Unique name for this onboarding step.
|
|
6460
|
+
* @param order - Optional explicit display order (accepts decimals, e.g. 2.1 for A/B variants).
|
|
6461
|
+
*/
|
|
6462
|
+
async step(stepName, order) {
|
|
6463
|
+
this.assertConfig();
|
|
6464
|
+
this.validateStepName(stepName, "step");
|
|
6465
|
+
this.lastStep = stepName;
|
|
6466
|
+
const stepPayload = { step_name: stepName };
|
|
6467
|
+
if (order !== void 0 && Number.isFinite(order) && order >= 0) {
|
|
6468
|
+
stepPayload.order = order;
|
|
6469
|
+
}
|
|
6470
|
+
const payload = {
|
|
6471
|
+
family: "onboarding",
|
|
6472
|
+
type: "step",
|
|
6473
|
+
...stepPayload
|
|
6474
|
+
};
|
|
6475
|
+
return this.emit("onboarding", payload, "step");
|
|
6476
|
+
}
|
|
6477
|
+
/**
|
|
6478
|
+
* Tracks successful completion of the onboarding flow.
|
|
6479
|
+
* Marks the flow as finished.
|
|
6480
|
+
*/
|
|
6481
|
+
async complete() {
|
|
6482
|
+
this.assertConfig();
|
|
6483
|
+
this.finished = true;
|
|
6484
|
+
return this.emit("onboarding", { family: "onboarding", type: "complete" }, "complete");
|
|
6485
|
+
}
|
|
6486
|
+
/**
|
|
6487
|
+
* Tracks an explicit drop (abandonment) at the given step.
|
|
6488
|
+
* Marks the flow as finished.
|
|
6489
|
+
*
|
|
6490
|
+
* @param stepName - The step name where the user dropped off.
|
|
6491
|
+
*/
|
|
6492
|
+
async drop(stepName) {
|
|
6493
|
+
this.assertConfig();
|
|
6494
|
+
this.validateStepName(stepName, "drop");
|
|
6495
|
+
this.finished = true;
|
|
6496
|
+
const payload = {
|
|
6497
|
+
family: "onboarding",
|
|
6498
|
+
type: "drop",
|
|
6499
|
+
...{ step_name: stepName }
|
|
6500
|
+
};
|
|
6501
|
+
return this.emit("onboarding", payload, "drop");
|
|
6502
|
+
}
|
|
6503
|
+
/** Returns the last step name seen, or null if no step was tracked yet. */
|
|
6504
|
+
getLastStep() {
|
|
6505
|
+
return this.lastStep;
|
|
6506
|
+
}
|
|
6507
|
+
/** Returns whether the flow has been marked as finished (complete or drop). */
|
|
6508
|
+
isFinished() {
|
|
6509
|
+
return this.finished;
|
|
6510
|
+
}
|
|
6511
|
+
async emit(eventName, properties, logLabel) {
|
|
6512
|
+
const pipeline = this.pipeline;
|
|
6513
|
+
const distinctId = pipeline.getDistinctId();
|
|
6514
|
+
if (!distinctId) {
|
|
6515
|
+
if (this.debug) console.log(`[Paywallo:Onboarding] skipped (no distinctId): ${logLabel}`);
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
6518
|
+
await pipeline.trackEvent(eventName, distinctId, properties);
|
|
6519
|
+
if (this.debug) {
|
|
6520
|
+
console.log(`[Paywallo:Onboarding] event emitted: ${eventName}.${logLabel}`, properties);
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
assertConfig() {
|
|
6524
|
+
if (!this.pipeline) {
|
|
6525
|
+
throw new OnboardingError(
|
|
6526
|
+
ONBOARDING_ERROR_CODES.NOT_INITIALIZED,
|
|
6527
|
+
"OnboardingManager not initialized. Call Paywallo.init() first."
|
|
6528
|
+
);
|
|
6529
|
+
}
|
|
6530
|
+
}
|
|
6531
|
+
validateStepName(stepName, method) {
|
|
6532
|
+
if (typeof stepName !== "string" || stepName.trim().length === 0) {
|
|
6533
|
+
throw new OnboardingError(
|
|
6534
|
+
ONBOARDING_ERROR_CODES.INVALID_STEP_NAME,
|
|
6535
|
+
`OnboardingManager.${method}(): stepName must be a non-empty string.`
|
|
6536
|
+
);
|
|
6537
|
+
}
|
|
6538
|
+
}
|
|
6539
|
+
};
|
|
6540
|
+
onboardingManager = new OnboardingManager();
|
|
6541
|
+
}
|
|
6542
|
+
});
|
|
6543
|
+
|
|
6544
|
+
// src/domains/onboarding/index.ts
|
|
6545
|
+
var init_onboarding = __esm({
|
|
6546
|
+
"src/domains/onboarding/index.ts"() {
|
|
6547
|
+
"use strict";
|
|
6548
|
+
init_OnboardingError();
|
|
6549
|
+
init_OnboardingManager();
|
|
6379
6550
|
}
|
|
6380
6551
|
});
|
|
6381
6552
|
|
|
@@ -6594,18 +6765,6 @@ async function trackEvent(apiClient, state, eventName, options) {
|
|
|
6594
6765
|
options?.priority ? { priority: options.priority } : void 0
|
|
6595
6766
|
);
|
|
6596
6767
|
}
|
|
6597
|
-
async function trackOnboardingStep(apiClient, state, index, name) {
|
|
6598
|
-
const distinctId = identityManager.getDistinctId();
|
|
6599
|
-
if (!distinctId) return;
|
|
6600
|
-
if (!Number.isInteger(index) || index < 0) {
|
|
6601
|
-
const msg = `Invalid stepIndex: "${index}". Must be a non-negative integer.`;
|
|
6602
|
-
throw new AnalyticsError(ANALYTICS_ERROR_CODES.INVALID_STEP_INDEX, msg);
|
|
6603
|
-
}
|
|
6604
|
-
const now = Date.now();
|
|
6605
|
-
const timeOnPreviousStep = state.lastOnboardingStepTimestamp !== null ? Math.round((now - state.lastOnboardingStepTimestamp) / 1e3) : 0;
|
|
6606
|
-
state.lastOnboardingStepTimestamp = now;
|
|
6607
|
-
await apiClient.trackEvent("$onboarding_step", distinctId, { stepIndex: index, stepName: name, timeOnPreviousStep });
|
|
6608
|
-
}
|
|
6609
6768
|
function validateCoreAction(actionName) {
|
|
6610
6769
|
if (!actionName || typeof actionName !== "string") {
|
|
6611
6770
|
const msg = `Invalid actionName: "${actionName}". Must be a non-empty string.`;
|
|
@@ -6669,138 +6828,6 @@ var init_PaywalloFlags = __esm({
|
|
|
6669
6828
|
}
|
|
6670
6829
|
});
|
|
6671
6830
|
|
|
6672
|
-
// src/domains/onboarding/OnboardingError.ts
|
|
6673
|
-
var OnboardingError, ONBOARDING_ERROR_CODES;
|
|
6674
|
-
var init_OnboardingError = __esm({
|
|
6675
|
-
"src/domains/onboarding/OnboardingError.ts"() {
|
|
6676
|
-
"use strict";
|
|
6677
|
-
init_PaywalloError();
|
|
6678
|
-
OnboardingError = class extends PaywalloError {
|
|
6679
|
-
constructor(code, message) {
|
|
6680
|
-
super("onboarding", code, message);
|
|
6681
|
-
this.name = "OnboardingError";
|
|
6682
|
-
}
|
|
6683
|
-
};
|
|
6684
|
-
ONBOARDING_ERROR_CODES = {
|
|
6685
|
-
NOT_INITIALIZED: "ONBOARDING_NOT_INITIALIZED",
|
|
6686
|
-
INVALID_STEP_NAME: "ONBOARDING_INVALID_STEP_NAME"
|
|
6687
|
-
};
|
|
6688
|
-
}
|
|
6689
|
-
});
|
|
6690
|
-
|
|
6691
|
-
// src/domains/onboarding/OnboardingManager.ts
|
|
6692
|
-
var OnboardingManager, onboardingManager;
|
|
6693
|
-
var init_OnboardingManager = __esm({
|
|
6694
|
-
"src/domains/onboarding/OnboardingManager.ts"() {
|
|
6695
|
-
"use strict";
|
|
6696
|
-
init_OnboardingError();
|
|
6697
|
-
OnboardingManager = class {
|
|
6698
|
-
constructor() {
|
|
6699
|
-
this.pipeline = null;
|
|
6700
|
-
this.debug = false;
|
|
6701
|
-
this.lastStep = null;
|
|
6702
|
-
this.finished = false;
|
|
6703
|
-
}
|
|
6704
|
-
/**
|
|
6705
|
-
* Injects runtime dependencies. Called by PaywalloClient during init.
|
|
6706
|
-
*/
|
|
6707
|
-
injectDeps(config) {
|
|
6708
|
-
this.pipeline = config.pipeline;
|
|
6709
|
-
this.debug = config.debug ?? false;
|
|
6710
|
-
}
|
|
6711
|
-
/**
|
|
6712
|
-
* Tracks an onboarding step view.
|
|
6713
|
-
* Saves the step name internally for implicit drop detection on the backend.
|
|
6714
|
-
*
|
|
6715
|
-
* @param stepName - Unique name for this onboarding step.
|
|
6716
|
-
*/
|
|
6717
|
-
async step(stepName) {
|
|
6718
|
-
this.assertConfig();
|
|
6719
|
-
this.validateStepName(stepName, "step");
|
|
6720
|
-
this.lastStep = stepName;
|
|
6721
|
-
const payload = {
|
|
6722
|
-
family: "onboarding",
|
|
6723
|
-
type: "step",
|
|
6724
|
-
...{ step_name: stepName }
|
|
6725
|
-
};
|
|
6726
|
-
return this.emit("onboarding", payload, "step");
|
|
6727
|
-
}
|
|
6728
|
-
/**
|
|
6729
|
-
* Tracks successful completion of the onboarding flow.
|
|
6730
|
-
* Marks the flow as finished.
|
|
6731
|
-
*/
|
|
6732
|
-
async complete() {
|
|
6733
|
-
this.assertConfig();
|
|
6734
|
-
this.finished = true;
|
|
6735
|
-
return this.emit("onboarding", { family: "onboarding", type: "complete" }, "complete");
|
|
6736
|
-
}
|
|
6737
|
-
/**
|
|
6738
|
-
* Tracks an explicit drop (abandonment) at the given step.
|
|
6739
|
-
* Marks the flow as finished.
|
|
6740
|
-
*
|
|
6741
|
-
* @param stepName - The step name where the user dropped off.
|
|
6742
|
-
*/
|
|
6743
|
-
async drop(stepName) {
|
|
6744
|
-
this.assertConfig();
|
|
6745
|
-
this.validateStepName(stepName, "drop");
|
|
6746
|
-
this.finished = true;
|
|
6747
|
-
const payload = {
|
|
6748
|
-
family: "onboarding",
|
|
6749
|
-
type: "drop",
|
|
6750
|
-
...{ step_name: stepName }
|
|
6751
|
-
};
|
|
6752
|
-
return this.emit("onboarding", payload, "drop");
|
|
6753
|
-
}
|
|
6754
|
-
/** Returns the last step name seen, or null if no step was tracked yet. */
|
|
6755
|
-
getLastStep() {
|
|
6756
|
-
return this.lastStep;
|
|
6757
|
-
}
|
|
6758
|
-
/** Returns whether the flow has been marked as finished (complete or drop). */
|
|
6759
|
-
isFinished() {
|
|
6760
|
-
return this.finished;
|
|
6761
|
-
}
|
|
6762
|
-
async emit(eventName, properties, logLabel) {
|
|
6763
|
-
const pipeline = this.pipeline;
|
|
6764
|
-
const distinctId = pipeline.getDistinctId();
|
|
6765
|
-
if (!distinctId) {
|
|
6766
|
-
if (this.debug) console.log(`[Paywallo:Onboarding] skipped (no distinctId): ${logLabel}`);
|
|
6767
|
-
return;
|
|
6768
|
-
}
|
|
6769
|
-
await pipeline.trackEvent(eventName, distinctId, properties);
|
|
6770
|
-
if (this.debug) {
|
|
6771
|
-
console.log(`[Paywallo:Onboarding] event emitted: ${eventName}.${logLabel}`, properties);
|
|
6772
|
-
}
|
|
6773
|
-
}
|
|
6774
|
-
assertConfig() {
|
|
6775
|
-
if (!this.pipeline) {
|
|
6776
|
-
throw new OnboardingError(
|
|
6777
|
-
ONBOARDING_ERROR_CODES.NOT_INITIALIZED,
|
|
6778
|
-
"OnboardingManager not initialized. Call Paywallo.init() first."
|
|
6779
|
-
);
|
|
6780
|
-
}
|
|
6781
|
-
}
|
|
6782
|
-
validateStepName(stepName, method) {
|
|
6783
|
-
if (typeof stepName !== "string" || stepName.trim().length === 0) {
|
|
6784
|
-
throw new OnboardingError(
|
|
6785
|
-
ONBOARDING_ERROR_CODES.INVALID_STEP_NAME,
|
|
6786
|
-
`OnboardingManager.${method}(): stepName must be a non-empty string.`
|
|
6787
|
-
);
|
|
6788
|
-
}
|
|
6789
|
-
}
|
|
6790
|
-
};
|
|
6791
|
-
onboardingManager = new OnboardingManager();
|
|
6792
|
-
}
|
|
6793
|
-
});
|
|
6794
|
-
|
|
6795
|
-
// src/domains/onboarding/index.ts
|
|
6796
|
-
var init_onboarding = __esm({
|
|
6797
|
-
"src/domains/onboarding/index.ts"() {
|
|
6798
|
-
"use strict";
|
|
6799
|
-
init_OnboardingError();
|
|
6800
|
-
init_OnboardingManager();
|
|
6801
|
-
}
|
|
6802
|
-
});
|
|
6803
|
-
|
|
6804
6831
|
// src/domains/paywall/paywallHeartbeatRecovery.ts
|
|
6805
6832
|
async function recoverPaywallHeartbeat(apiClient, distinctId, sessionId, debug) {
|
|
6806
6833
|
const snapshot = await readPersistedHeartbeat();
|
|
@@ -7132,6 +7159,36 @@ var init_SubscriptionManager = __esm({
|
|
|
7132
7159
|
}
|
|
7133
7160
|
});
|
|
7134
7161
|
|
|
7162
|
+
// src/utils/detectEnvironment.ts
|
|
7163
|
+
import { NativeModules as NativeModules7 } from "react-native";
|
|
7164
|
+
async function detectEnvironment() {
|
|
7165
|
+
if (cached !== null) return cached;
|
|
7166
|
+
if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
|
|
7167
|
+
cached = "sandbox";
|
|
7168
|
+
return cached;
|
|
7169
|
+
}
|
|
7170
|
+
if (!nativeModule) {
|
|
7171
|
+
cached = "production";
|
|
7172
|
+
return cached;
|
|
7173
|
+
}
|
|
7174
|
+
try {
|
|
7175
|
+
const result = await nativeModule.detect();
|
|
7176
|
+
cached = result === "sandbox" ? "sandbox" : "production";
|
|
7177
|
+
return cached;
|
|
7178
|
+
} catch {
|
|
7179
|
+
cached = "production";
|
|
7180
|
+
return cached;
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
var nativeModule, cached;
|
|
7184
|
+
var init_detectEnvironment = __esm({
|
|
7185
|
+
"src/utils/detectEnvironment.ts"() {
|
|
7186
|
+
"use strict";
|
|
7187
|
+
nativeModule = NativeModules7.PaywalloEnv ?? null;
|
|
7188
|
+
cached = null;
|
|
7189
|
+
}
|
|
7190
|
+
});
|
|
7191
|
+
|
|
7135
7192
|
// src/domains/iap/apiPurchaseMethods.ts
|
|
7136
7193
|
async function validatePurchase(client, appKey, platform, receipt, productId, transactionId, priceLocal, currency, country, distinctId, paywallPlacement, variantKey) {
|
|
7137
7194
|
const response = await client.post(
|
|
@@ -7457,7 +7514,7 @@ var init_ApiClientQueue = __esm({
|
|
|
7457
7514
|
});
|
|
7458
7515
|
|
|
7459
7516
|
// src/core/eventEnvelopeV2.ts
|
|
7460
|
-
import { Platform as
|
|
7517
|
+
import { Platform as Platform14 } from "react-native";
|
|
7461
7518
|
import { z as z2 } from "zod";
|
|
7462
7519
|
function buildV2Envelope(events, providerContext) {
|
|
7463
7520
|
const context = { ...providerContext };
|
|
@@ -7473,21 +7530,42 @@ function buildV2Envelope(events, providerContext) {
|
|
|
7473
7530
|
if (family === "custom") {
|
|
7474
7531
|
payload.event_name = event.eventName;
|
|
7475
7532
|
}
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
payload
|
|
7481
|
-
}
|
|
7533
|
+
const candidateId = payload.installEventId;
|
|
7534
|
+
let id;
|
|
7535
|
+
if (typeof candidateId === "string" && isValidUUIDv4(candidateId)) {
|
|
7536
|
+
id = candidateId;
|
|
7537
|
+
delete payload.installEventId;
|
|
7538
|
+
} else {
|
|
7539
|
+
id = generateUUID();
|
|
7540
|
+
}
|
|
7541
|
+
return { id, ts: event.timestamp, name: family, payload };
|
|
7482
7542
|
});
|
|
7483
7543
|
if (context.sdk_version === void 0) context.sdk_version = SDK_VERSION;
|
|
7484
|
-
if (context.platform === void 0) context.platform =
|
|
7544
|
+
if (context.platform === void 0) context.platform = Platform14.OS;
|
|
7485
7545
|
if (context.distinct_id === void 0 && events.length > 0) {
|
|
7486
7546
|
context.distinct_id = events[0].distinctId;
|
|
7487
7547
|
}
|
|
7488
7548
|
if (!context.distinct_id || context.distinct_id.length === 0) {
|
|
7489
7549
|
console.error("[Paywallo:ENVELOPE] distinct_id is empty after resolution \u2014 envelope will fail schema", { providerContext, eventCount: events.length, firstEventName: events[0]?.eventName });
|
|
7490
7550
|
}
|
|
7551
|
+
const idsFromProps = {};
|
|
7552
|
+
const existingIds = context.ids;
|
|
7553
|
+
for (const event of events) {
|
|
7554
|
+
for (const { key, aliases } of IDS_PROMO_ALIASES) {
|
|
7555
|
+
if (existingIds?.[key] !== void 0) continue;
|
|
7556
|
+
if (idsFromProps[key] !== void 0) continue;
|
|
7557
|
+
for (const alias of aliases) {
|
|
7558
|
+
const val = event.properties[alias];
|
|
7559
|
+
if (typeof val === "string" && val.length > 0) {
|
|
7560
|
+
idsFromProps[key] = val;
|
|
7561
|
+
break;
|
|
7562
|
+
}
|
|
7563
|
+
}
|
|
7564
|
+
}
|
|
7565
|
+
}
|
|
7566
|
+
if (Object.keys(idsFromProps).length > 0) {
|
|
7567
|
+
context.ids = { ...idsFromProps, ...context.ids };
|
|
7568
|
+
}
|
|
7491
7569
|
return { context, events: v2Events };
|
|
7492
7570
|
}
|
|
7493
7571
|
function resolveProviderContext(provider) {
|
|
@@ -7521,7 +7599,7 @@ function splitPayloadAndContext(properties) {
|
|
|
7521
7599
|
}
|
|
7522
7600
|
return { payload, promoted };
|
|
7523
7601
|
}
|
|
7524
|
-
var v2EventSchema, v2ContextSchema, v2EnvelopeSchema, CONTEXT_KEY_ALIASES;
|
|
7602
|
+
var v2EventSchema, v2ContextSchema, v2EnvelopeSchema, IDS_PROMO_ALIASES, CONTEXT_KEY_ALIASES;
|
|
7525
7603
|
var init_eventEnvelopeV2 = __esm({
|
|
7526
7604
|
"src/core/eventEnvelopeV2.ts"() {
|
|
7527
7605
|
"use strict";
|
|
@@ -7547,6 +7625,7 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7547
7625
|
device_model: z2.string().optional(),
|
|
7548
7626
|
timezone: z2.string().optional(),
|
|
7549
7627
|
locale: z2.string().optional(),
|
|
7628
|
+
country: z2.string().optional(),
|
|
7550
7629
|
carrier: z2.string().optional(),
|
|
7551
7630
|
screen_width: z2.number().optional(),
|
|
7552
7631
|
screen_height: z2.number().optional(),
|
|
@@ -7558,6 +7637,12 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7558
7637
|
context: v2ContextSchema,
|
|
7559
7638
|
events: z2.array(v2EventSchema).min(1)
|
|
7560
7639
|
});
|
|
7640
|
+
IDS_PROMO_ALIASES = [
|
|
7641
|
+
{ key: "idfv", aliases: ["idfv"] },
|
|
7642
|
+
{ key: "gaid", aliases: ["gaid"] },
|
|
7643
|
+
{ key: "fb_anon_id", aliases: ["fbAnonId", "fb_anon_id"] },
|
|
7644
|
+
{ key: "idfa", aliases: ["idfa"] }
|
|
7645
|
+
];
|
|
7561
7646
|
CONTEXT_KEY_ALIASES = {
|
|
7562
7647
|
distinct_id: ["distinct_id", "distinctId"],
|
|
7563
7648
|
session_id: ["session_id", "sessionId"],
|
|
@@ -7574,6 +7659,7 @@ var init_eventEnvelopeV2 = __esm({
|
|
|
7574
7659
|
device_model: ["device_model", "deviceModel", "model"],
|
|
7575
7660
|
timezone: ["timezone", "timeZone"],
|
|
7576
7661
|
locale: ["locale"],
|
|
7662
|
+
country: ["country", "regionCode"],
|
|
7577
7663
|
carrier: ["carrier_ctx"],
|
|
7578
7664
|
screen_width: ["screen_width"],
|
|
7579
7665
|
screen_height: ["screen_height"],
|
|
@@ -7593,7 +7679,7 @@ var init_events = __esm({
|
|
|
7593
7679
|
});
|
|
7594
7680
|
|
|
7595
7681
|
// src/core/EventBatcher.ts
|
|
7596
|
-
import { Platform as
|
|
7682
|
+
import { Platform as Platform15 } from "react-native";
|
|
7597
7683
|
var BATCH_MAX_SIZE, BATCH_FLUSH_MS, EVENT_NAME_REGEX, V2_BATCH_ENDPOINT, EventBatcher;
|
|
7598
7684
|
var init_EventBatcher = __esm({
|
|
7599
7685
|
"src/core/EventBatcher.ts"() {
|
|
@@ -7646,7 +7732,7 @@ var init_EventBatcher = __esm({
|
|
|
7646
7732
|
const event = {
|
|
7647
7733
|
eventName,
|
|
7648
7734
|
distinctId,
|
|
7649
|
-
properties: { ...properties, platform:
|
|
7735
|
+
properties: { ...properties, platform: Platform15.OS },
|
|
7650
7736
|
timestamp: timestamp ?? Date.now(),
|
|
7651
7737
|
environment: environment.toLowerCase()
|
|
7652
7738
|
};
|
|
@@ -7972,7 +8058,7 @@ var init_http = __esm({
|
|
|
7972
8058
|
});
|
|
7973
8059
|
|
|
7974
8060
|
// src/core/ApiClient.ts
|
|
7975
|
-
import { Platform as
|
|
8061
|
+
import { Platform as Platform16 } from "react-native";
|
|
7976
8062
|
function normalizeDateOfBirth(raw) {
|
|
7977
8063
|
if (!raw) return void 0;
|
|
7978
8064
|
if (DATE_OF_BIRTH_RE.test(raw)) return raw;
|
|
@@ -8108,7 +8194,7 @@ var init_ApiClient = __esm({
|
|
|
8108
8194
|
buildSdkHeaders() {
|
|
8109
8195
|
return {
|
|
8110
8196
|
"x-sdk-version": SDK_VERSION,
|
|
8111
|
-
"x-sdk-platform":
|
|
8197
|
+
"x-sdk-platform": Platform16.OS,
|
|
8112
8198
|
"x-sdk-environment": this.environment
|
|
8113
8199
|
};
|
|
8114
8200
|
}
|
|
@@ -8138,7 +8224,7 @@ var init_ApiClient = __esm({
|
|
|
8138
8224
|
message,
|
|
8139
8225
|
context,
|
|
8140
8226
|
sdkVersion: SDK_VERSION,
|
|
8141
|
-
platform:
|
|
8227
|
+
platform: Platform16.OS
|
|
8142
8228
|
}, true);
|
|
8143
8229
|
} catch (err) {
|
|
8144
8230
|
if (this.debug) console.log("[Paywallo:ApiClient] reportError failed", err);
|
|
@@ -8156,7 +8242,7 @@ var init_ApiClient = __esm({
|
|
|
8156
8242
|
async identify(distinctId, properties, email, deviceId, pii) {
|
|
8157
8243
|
const rawTraits = {
|
|
8158
8244
|
email: email || void 0,
|
|
8159
|
-
platform:
|
|
8245
|
+
platform: Platform16.OS,
|
|
8160
8246
|
name: properties?.name,
|
|
8161
8247
|
country: properties?.country,
|
|
8162
8248
|
locale: properties?.locale,
|
|
@@ -8352,7 +8438,7 @@ function setupNotifications(apiClient, config, environment, eventPipeline) {
|
|
|
8352
8438
|
notificationsManager.setupHandlers({ eventBatcher: eventPipeline });
|
|
8353
8439
|
notificationsManager.initialize({
|
|
8354
8440
|
appKey: config.appKey,
|
|
8355
|
-
apiBaseUrl:
|
|
8441
|
+
apiBaseUrl: DEFAULT_API_URL,
|
|
8356
8442
|
debug: config.debug,
|
|
8357
8443
|
environment: environment === "Sandbox" ? "sandbox" : "production"
|
|
8358
8444
|
}).catch((err) => {
|
|
@@ -8431,36 +8517,6 @@ var init_PaywalloState = __esm({
|
|
|
8431
8517
|
}
|
|
8432
8518
|
});
|
|
8433
8519
|
|
|
8434
|
-
// src/utils/detectEnvironment.ts
|
|
8435
|
-
import { NativeModules as NativeModules8 } from "react-native";
|
|
8436
|
-
async function detectEnvironment() {
|
|
8437
|
-
if (cached !== null) return cached;
|
|
8438
|
-
if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
|
|
8439
|
-
cached = "sandbox";
|
|
8440
|
-
return cached;
|
|
8441
|
-
}
|
|
8442
|
-
if (!nativeModule) {
|
|
8443
|
-
cached = "production";
|
|
8444
|
-
return cached;
|
|
8445
|
-
}
|
|
8446
|
-
try {
|
|
8447
|
-
const result = await nativeModule.detect();
|
|
8448
|
-
cached = result === "sandbox" ? "sandbox" : "production";
|
|
8449
|
-
return cached;
|
|
8450
|
-
} catch {
|
|
8451
|
-
cached = "production";
|
|
8452
|
-
return cached;
|
|
8453
|
-
}
|
|
8454
|
-
}
|
|
8455
|
-
var nativeModule, cached;
|
|
8456
|
-
var init_detectEnvironment = __esm({
|
|
8457
|
-
"src/utils/detectEnvironment.ts"() {
|
|
8458
|
-
"use strict";
|
|
8459
|
-
nativeModule = NativeModules8.PaywalloEnv ?? null;
|
|
8460
|
-
cached = null;
|
|
8461
|
-
}
|
|
8462
|
-
});
|
|
8463
|
-
|
|
8464
8520
|
// src/core/PaywalloInitializer.ts
|
|
8465
8521
|
import { Dimensions as Dimensions4, PixelRatio as PixelRatio2 } from "react-native";
|
|
8466
8522
|
async function initWithRetry(state, config) {
|
|
@@ -8507,7 +8563,7 @@ function reportInitFailure(state, config, error, reason) {
|
|
|
8507
8563
|
try {
|
|
8508
8564
|
const tempClient = new ApiClient(
|
|
8509
8565
|
config.appKey,
|
|
8510
|
-
|
|
8566
|
+
DEFAULT_API_URL,
|
|
8511
8567
|
config.debug
|
|
8512
8568
|
);
|
|
8513
8569
|
void tempClient.reportError("INIT_FAILED", reason, {
|
|
@@ -8557,7 +8613,7 @@ async function doInit(state, config) {
|
|
|
8557
8613
|
]);
|
|
8558
8614
|
const apiClient = new ApiClient(
|
|
8559
8615
|
config.appKey,
|
|
8560
|
-
|
|
8616
|
+
DEFAULT_API_URL,
|
|
8561
8617
|
config.debug,
|
|
8562
8618
|
environment,
|
|
8563
8619
|
offlineQueueEnabled,
|
|
@@ -8631,8 +8687,8 @@ async function doInit(state, config) {
|
|
|
8631
8687
|
let timezone;
|
|
8632
8688
|
try {
|
|
8633
8689
|
const opts = Intl.DateTimeFormat().resolvedOptions();
|
|
8634
|
-
locale = opts.locale || void 0;
|
|
8635
|
-
timezone = opts.timeZone || void 0;
|
|
8690
|
+
locale = device?.languageTag || opts.locale || void 0;
|
|
8691
|
+
timezone = device?.timeZone || opts.timeZone || void 0;
|
|
8636
8692
|
} catch {
|
|
8637
8693
|
}
|
|
8638
8694
|
let screenWidth;
|
|
@@ -8656,7 +8712,7 @@ async function doInit(state, config) {
|
|
|
8656
8712
|
device_model: device?.modelId || device?.model || void 0,
|
|
8657
8713
|
timezone,
|
|
8658
8714
|
locale,
|
|
8659
|
-
|
|
8715
|
+
...device?.regionCode && { country: device.regionCode },
|
|
8660
8716
|
screen_width: screenWidth,
|
|
8661
8717
|
screen_height: screenHeight,
|
|
8662
8718
|
screen_density: screenDensity,
|
|
@@ -8722,6 +8778,7 @@ var init_PaywalloInitializer = __esm({
|
|
|
8722
8778
|
init_plan();
|
|
8723
8779
|
init_session();
|
|
8724
8780
|
init_SubscriptionManager();
|
|
8781
|
+
init_detectEnvironment();
|
|
8725
8782
|
init_NativeDeviceInfo();
|
|
8726
8783
|
init_ApiClient();
|
|
8727
8784
|
init_constants();
|
|
@@ -8731,7 +8788,6 @@ var init_PaywalloInitializer = __esm({
|
|
|
8731
8788
|
init_PaywalloState();
|
|
8732
8789
|
init_queue();
|
|
8733
8790
|
init_NativeStorage();
|
|
8734
|
-
init_detectEnvironment();
|
|
8735
8791
|
}
|
|
8736
8792
|
});
|
|
8737
8793
|
|
|
@@ -8852,6 +8908,7 @@ var init_PaywalloClient = __esm({
|
|
|
8852
8908
|
init_plan();
|
|
8853
8909
|
init_session();
|
|
8854
8910
|
init_ClientError();
|
|
8911
|
+
init_onboarding();
|
|
8855
8912
|
init_network();
|
|
8856
8913
|
init_PaywalloAnalytics();
|
|
8857
8914
|
init_PaywalloFlags();
|
|
@@ -8921,8 +8978,9 @@ var init_PaywalloClient = __esm({
|
|
|
8921
8978
|
async track(eventName, options) {
|
|
8922
8979
|
return trackEvent(this.getApiClientOrThrow(), this.state, eventName, options);
|
|
8923
8980
|
}
|
|
8924
|
-
async onboardingStep(
|
|
8925
|
-
|
|
8981
|
+
async onboardingStep(order, name) {
|
|
8982
|
+
this.ensureInitialized();
|
|
8983
|
+
return onboardingManager.step(name, order);
|
|
8926
8984
|
}
|
|
8927
8985
|
async coreAction(actionName) {
|
|
8928
8986
|
this.ensureInitialized();
|
|
@@ -9009,6 +9067,9 @@ var init_PaywalloClient = __esm({
|
|
|
9009
9067
|
getConfig() {
|
|
9010
9068
|
return this.state.config;
|
|
9011
9069
|
}
|
|
9070
|
+
getId() {
|
|
9071
|
+
return identityManager.getDistinctId();
|
|
9072
|
+
}
|
|
9012
9073
|
getDistinctId() {
|
|
9013
9074
|
return identityManager.getDistinctId();
|
|
9014
9075
|
}
|
|
@@ -9146,9 +9207,9 @@ __export(OfferingService_exports, {
|
|
|
9146
9207
|
OfferingService: () => OfferingService,
|
|
9147
9208
|
offeringService: () => offeringService
|
|
9148
9209
|
});
|
|
9149
|
-
import { Platform as
|
|
9210
|
+
import { Platform as Platform17 } from "react-native";
|
|
9150
9211
|
function resolveProductId(raw) {
|
|
9151
|
-
const isIos =
|
|
9212
|
+
const isIos = Platform17.OS === "ios";
|
|
9152
9213
|
const productId = isIos ? raw.apple_product_id : raw.google_product_id;
|
|
9153
9214
|
return productId ?? "";
|
|
9154
9215
|
}
|
|
@@ -9167,7 +9228,7 @@ function mapProduct2(raw) {
|
|
|
9167
9228
|
};
|
|
9168
9229
|
}
|
|
9169
9230
|
function pickPlatformProduct(products) {
|
|
9170
|
-
const isIos =
|
|
9231
|
+
const isIos = Platform17.OS === "ios";
|
|
9171
9232
|
const match = products.find((p) => isIos ? p.apple_product_id : p.google_product_id);
|
|
9172
9233
|
return match ?? products[0] ?? null;
|
|
9173
9234
|
}
|
|
@@ -9394,7 +9455,7 @@ init_onboarding();
|
|
|
9394
9455
|
import { useCallback as useCallback9 } from "react";
|
|
9395
9456
|
function useOnboarding() {
|
|
9396
9457
|
const step = useCallback9(
|
|
9397
|
-
(stepName) => onboardingManager.step(stepName),
|
|
9458
|
+
(stepName, order) => onboardingManager.step(stepName, order),
|
|
9398
9459
|
[]
|
|
9399
9460
|
);
|
|
9400
9461
|
const complete = useCallback9(
|
|
@@ -9738,8 +9799,41 @@ function useSubscription() {
|
|
|
9738
9799
|
};
|
|
9739
9800
|
}
|
|
9740
9801
|
|
|
9802
|
+
// src/hooks/usePaywalloScreenTracking.ts
|
|
9803
|
+
init_PaywalloClient();
|
|
9804
|
+
import { useCallback as useCallback15, useRef as useRef8 } from "react";
|
|
9805
|
+
function isNavState(value) {
|
|
9806
|
+
return typeof value === "object" && value !== null && "routes" in value && "index" in value && Array.isArray(value.routes) && typeof value.index === "number";
|
|
9807
|
+
}
|
|
9808
|
+
function getActiveRouteName(state) {
|
|
9809
|
+
try {
|
|
9810
|
+
if (!isNavState(state)) return null;
|
|
9811
|
+
const route = state.routes[state.index];
|
|
9812
|
+
if (!route) return null;
|
|
9813
|
+
if (isNavState(route.state)) {
|
|
9814
|
+
return getActiveRouteName(route.state);
|
|
9815
|
+
}
|
|
9816
|
+
return typeof route.name === "string" ? route.name : null;
|
|
9817
|
+
} catch {
|
|
9818
|
+
return null;
|
|
9819
|
+
}
|
|
9820
|
+
}
|
|
9821
|
+
function usePaywalloScreenTracking() {
|
|
9822
|
+
const lastScreenRef = useRef8(null);
|
|
9823
|
+
return useCallback15((state) => {
|
|
9824
|
+
if (!PaywalloClient.isReady()) return;
|
|
9825
|
+
const screenName = getActiveRouteName(state);
|
|
9826
|
+
if (!screenName || screenName === lastScreenRef.current) return;
|
|
9827
|
+
lastScreenRef.current = screenName;
|
|
9828
|
+
void PaywalloClient.track("screen_view", {
|
|
9829
|
+
properties: { screen_name: screenName }
|
|
9830
|
+
}).catch(() => {
|
|
9831
|
+
});
|
|
9832
|
+
}, []);
|
|
9833
|
+
}
|
|
9834
|
+
|
|
9741
9835
|
// src/PaywalloProvider.tsx
|
|
9742
|
-
import { useCallback as
|
|
9836
|
+
import { useCallback as useCallback20, useEffect as useEffect14, useLayoutEffect, useMemo as useMemo3, useRef as useRef12, useState as useState17 } from "react";
|
|
9743
9837
|
import { Animated as Animated4, Dimensions as Dimensions5, Easing as Easing2, StyleSheet as StyleSheet5 } from "react-native";
|
|
9744
9838
|
init_PaywalloClient();
|
|
9745
9839
|
init_NativeStorage();
|
|
@@ -9962,50 +10056,9 @@ function buildCallbacks() {
|
|
|
9962
10056
|
const identifier = "paywallIdentifier" in safe && typeof safe.paywallIdentifier === "string" ? safe.paywallIdentifier : productId;
|
|
9963
10057
|
log2("onPurchase", { productId, identifier });
|
|
9964
10058
|
void trackPaywallEvent("purchased", identifier, ts, { product_id: productId });
|
|
9965
|
-
},
|
|
9966
|
-
// Global Superwall event listener — used specifically for `transactionComplete`
|
|
9967
|
-
// which is the only event that exposes the full product (currency/price) +
|
|
9968
|
-
// transaction (storeTransactionId) shape needed to create a server-side
|
|
9969
|
-
// `transactions` row. Other events are skipped (paywallOpen/Dismiss already
|
|
9970
|
-
// handled above with their typed callbacks).
|
|
9971
|
-
onSuperwallEvent: (info) => {
|
|
9972
|
-
const ev = info?.event;
|
|
9973
|
-
if (!ev || ev.event !== "transactionComplete") return;
|
|
9974
|
-
const ts = Date.now();
|
|
9975
|
-
const product = ev.product;
|
|
9976
|
-
const transaction = ev.transaction;
|
|
9977
|
-
if (!product) {
|
|
9978
|
-
log2("transactionComplete missing product \u2014 skipping transaction track");
|
|
9979
|
-
return;
|
|
9980
|
-
}
|
|
9981
|
-
const productId = product.productIdentifier ?? product.id ?? "unknown";
|
|
9982
|
-
const currency = product.currencyCode ?? "USD";
|
|
9983
|
-
const price = product.price ?? 0;
|
|
9984
|
-
const transactionId = transaction?.storeTransactionId ?? transaction?.originalTransactionIdentifier ?? `${productId}_${String(ts)}`;
|
|
9985
|
-
const isTrial = product.hasFreeTrial === true || (product.trialPeriodPrice ?? 0) > 0;
|
|
9986
|
-
const paywallIdentifier = ev.paywallInfo?.identifier;
|
|
9987
|
-
log2("onSuperwallEvent: transactionComplete", { productId, currency, price, transactionId, isTrial });
|
|
9988
|
-
void (async () => {
|
|
9989
|
-
try {
|
|
9990
|
-
await PaywalloClient.track("transaction", {
|
|
9991
|
-
priority: "critical",
|
|
9992
|
-
properties: {
|
|
9993
|
-
type: isTrial ? "trial_started" : "completed",
|
|
9994
|
-
// Server's IngestTranslator looks for `transaction_id`/`product_id`
|
|
9995
|
-
// /`amount`/`currency`/`paywall_id` keys (not `tx_id`). PurchaseHandler
|
|
9996
|
-
// then resolves type=trial/new/renewal based on amount being 0 vs >0.
|
|
9997
|
-
transaction_id: transactionId,
|
|
9998
|
-
product_id: productId,
|
|
9999
|
-
amount: price,
|
|
10000
|
-
currency,
|
|
10001
|
-
...paywallIdentifier ? { paywall_id: paywallIdentifier } : {}
|
|
10002
|
-
}
|
|
10003
|
-
});
|
|
10004
|
-
} catch (err) {
|
|
10005
|
-
log2("transactionComplete track error", { err: String(err) });
|
|
10006
|
-
}
|
|
10007
|
-
})();
|
|
10008
10059
|
}
|
|
10060
|
+
// onSuperwallEvent removed — transaction sale events are sourced exclusively
|
|
10061
|
+
// from server-side webhooks (Apple/Google/Superwall/RevenueCat).
|
|
10009
10062
|
};
|
|
10010
10063
|
}
|
|
10011
10064
|
function startSuperwallAutoBridge(debug = false) {
|
|
@@ -10049,7 +10102,7 @@ init_session();
|
|
|
10049
10102
|
init_ClientError();
|
|
10050
10103
|
|
|
10051
10104
|
// src/hooks/useAppAutoEvents.ts
|
|
10052
|
-
import { useEffect as useEffect13, useRef as
|
|
10105
|
+
import { useEffect as useEffect13, useRef as useRef9 } from "react";
|
|
10053
10106
|
|
|
10054
10107
|
// src/utils/platformDetection.ts
|
|
10055
10108
|
async function detectPlatform3() {
|
|
@@ -10075,7 +10128,7 @@ var FIRST_SEEN_KEY = "@paywallo:firstSeen_v226";
|
|
|
10075
10128
|
var DEBOUNCE_MS = 1e3;
|
|
10076
10129
|
function useAppAutoEvents(config) {
|
|
10077
10130
|
const { isInitialized, getAppVersion: getAppVersion2, getSessionId, emitLifecycle, storageGet, storageSet, debug } = config;
|
|
10078
|
-
const didRunRef =
|
|
10131
|
+
const didRunRef = useRef9(false);
|
|
10079
10132
|
useEffect13(() => {
|
|
10080
10133
|
if (debug) console.log("[Paywallo EVENTS] useEffect fired", { isInitialized, didRunRefCurrent: didRunRef.current });
|
|
10081
10134
|
if (!isInitialized || didRunRef.current) return;
|
|
@@ -10086,13 +10139,13 @@ function useAppAutoEvents(config) {
|
|
|
10086
10139
|
const sessionId = getSessionId();
|
|
10087
10140
|
const appVersion = getAppVersion2();
|
|
10088
10141
|
const deviceType = await detectPlatform3();
|
|
10089
|
-
const
|
|
10090
|
-
if (debug) console.log("[Paywallo EVENTS] computed device context", { deviceType, osVersion, appVersion, sessionId, hasSessionId: !!sessionId });
|
|
10142
|
+
const osVersion2 = await detectOsVersion();
|
|
10143
|
+
if (debug) console.log("[Paywallo EVENTS] computed device context", { deviceType, osVersion: osVersion2, appVersion, sessionId, hasSessionId: !!sessionId });
|
|
10091
10144
|
try {
|
|
10092
10145
|
if (debug) console.log("[Paywallo EVENTS] checking install \u2014 about to read FIRST_SEEN_KEY");
|
|
10093
10146
|
const firstSeen = await storageGet(FIRST_SEEN_KEY);
|
|
10094
10147
|
if (!firstSeen) {
|
|
10095
|
-
await emitLifecycle({ type: "install", device_type: deviceType, os_version:
|
|
10148
|
+
await emitLifecycle({ type: "install", device_type: deviceType, os_version: osVersion2, app_version: appVersion, ...sessionId ? { session_id: sessionId } : {} }, "critical");
|
|
10096
10149
|
await storageSet(FIRST_SEEN_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
10097
10150
|
if (debug) console.log("[Paywallo EVENTS] install event emitted (first time)");
|
|
10098
10151
|
if (debug) console.log("[Paywallo EVENTS] lifecycle install emitted");
|
|
@@ -10104,7 +10157,7 @@ function useAppAutoEvents(config) {
|
|
|
10104
10157
|
}
|
|
10105
10158
|
try {
|
|
10106
10159
|
if (debug) console.log("[Paywallo EVENTS] emitting cold_start");
|
|
10107
|
-
await emitLifecycle({ type: "cold_start", app_version: appVersion, device_type: deviceType, os_version:
|
|
10160
|
+
await emitLifecycle({ type: "cold_start", app_version: appVersion, device_type: deviceType, os_version: osVersion2, ...sessionId ? { session_id: sessionId } : {} }, "normal");
|
|
10108
10161
|
if (debug) console.log("[Paywallo EVENTS] lifecycle cold_start emitted");
|
|
10109
10162
|
} catch (err) {
|
|
10110
10163
|
if (debug) console.log("[Paywallo EVENTS] lifecycle cold_start failed", err);
|
|
@@ -10118,7 +10171,7 @@ function useAppAutoEvents(config) {
|
|
|
10118
10171
|
// src/hooks/useCampaignPreload.ts
|
|
10119
10172
|
init_PaywalloClient();
|
|
10120
10173
|
init_CampaignError();
|
|
10121
|
-
import { useCallback as
|
|
10174
|
+
import { useCallback as useCallback16, useRef as useRef10, useState as useState14 } from "react";
|
|
10122
10175
|
|
|
10123
10176
|
// src/utils/loadCampaignProducts.ts
|
|
10124
10177
|
init_IAPService();
|
|
@@ -10188,16 +10241,16 @@ function getCacheEntry(cache, placement) {
|
|
|
10188
10241
|
// src/hooks/useCampaignPreload.ts
|
|
10189
10242
|
function useCampaignPreload() {
|
|
10190
10243
|
const [preloadedWebView, setPreloadedWebView] = useState14(null);
|
|
10191
|
-
const preloadedCampaignsRef =
|
|
10192
|
-
const isPreloadValid =
|
|
10244
|
+
const preloadedCampaignsRef = useRef10(/* @__PURE__ */ new Map());
|
|
10245
|
+
const isPreloadValid = useCallback16(
|
|
10193
10246
|
(placement) => isCacheEntryValid(preloadedCampaignsRef.current.get(placement)),
|
|
10194
10247
|
[]
|
|
10195
10248
|
);
|
|
10196
|
-
const consumePreloadedCampaign =
|
|
10249
|
+
const consumePreloadedCampaign = useCallback16(
|
|
10197
10250
|
(placement) => getCacheEntry(preloadedCampaignsRef.current, placement),
|
|
10198
10251
|
[]
|
|
10199
10252
|
);
|
|
10200
|
-
const preloadCampaign =
|
|
10253
|
+
const preloadCampaign = useCallback16(
|
|
10201
10254
|
async (placement, context) => {
|
|
10202
10255
|
try {
|
|
10203
10256
|
const campaign = await PaywalloClient.getCampaign(placement, context);
|
|
@@ -10266,11 +10319,11 @@ function useCampaignPreload() {
|
|
|
10266
10319
|
}
|
|
10267
10320
|
|
|
10268
10321
|
// src/hooks/useProductLoader.ts
|
|
10269
|
-
import { useCallback as
|
|
10322
|
+
import { useCallback as useCallback17, useState as useState15 } from "react";
|
|
10270
10323
|
function useProductLoader() {
|
|
10271
10324
|
const [products, setProducts] = useState15(/* @__PURE__ */ new Map());
|
|
10272
10325
|
const [isLoadingProducts, setIsLoadingProducts] = useState15(false);
|
|
10273
|
-
const refreshProducts =
|
|
10326
|
+
const refreshProducts = useCallback17(async (productIds) => {
|
|
10274
10327
|
setIsLoadingProducts(true);
|
|
10275
10328
|
try {
|
|
10276
10329
|
const iapService = getIAPService();
|
|
@@ -10288,11 +10341,11 @@ function useProductLoader() {
|
|
|
10288
10341
|
}
|
|
10289
10342
|
|
|
10290
10343
|
// src/hooks/usePurchaseOrchestrator.ts
|
|
10291
|
-
import { useCallback as
|
|
10344
|
+
import { useCallback as useCallback18 } from "react";
|
|
10292
10345
|
init_paywall();
|
|
10293
10346
|
function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, invalidateSubscriptionCache) {
|
|
10294
10347
|
const { trackDismissed, trackProductSelected, trackPurchased } = usePaywallTracking();
|
|
10295
|
-
const handlePreloadedPurchase =
|
|
10348
|
+
const handlePreloadedPurchase = useCallback18(
|
|
10296
10349
|
async (productId) => {
|
|
10297
10350
|
try {
|
|
10298
10351
|
if (preloadedWebView) {
|
|
@@ -10330,7 +10383,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
10330
10383
|
},
|
|
10331
10384
|
[preloadedWebView, resolvePreloadedPaywall, clearPreloadedWebView, setShowingPreloadedWebView, presentedAtRef, trackDismissed, trackProductSelected, trackPurchased, invalidateSubscriptionCache]
|
|
10332
10385
|
);
|
|
10333
|
-
const handlePreloadedRestore =
|
|
10386
|
+
const handlePreloadedRestore = useCallback18(async () => {
|
|
10334
10387
|
try {
|
|
10335
10388
|
const transactions = await getIAPService().restore();
|
|
10336
10389
|
if (transactions.length === 0) return;
|
|
@@ -10355,7 +10408,7 @@ function usePurchaseOrchestrator(preloadedWebView, resolvePreloadedPaywall, clea
|
|
|
10355
10408
|
// src/hooks/useSubscriptionSync.ts
|
|
10356
10409
|
init_PaywalloClient();
|
|
10357
10410
|
init_SubscriptionCache();
|
|
10358
|
-
import { useCallback as
|
|
10411
|
+
import { useCallback as useCallback19, useRef as useRef11, useState as useState16 } from "react";
|
|
10359
10412
|
|
|
10360
10413
|
// src/hooks/subscriptionSyncHelpers.ts
|
|
10361
10414
|
init_SubscriptionCache();
|
|
@@ -10464,17 +10517,17 @@ async function checkPersistedCache(distinctId, onHit) {
|
|
|
10464
10517
|
// src/hooks/useSubscriptionSync.ts
|
|
10465
10518
|
function useSubscriptionSync() {
|
|
10466
10519
|
const [subscription, setSubscription] = useState16(null);
|
|
10467
|
-
const cacheRef =
|
|
10468
|
-
const setCacheAndState =
|
|
10520
|
+
const cacheRef = useRef11(null);
|
|
10521
|
+
const setCacheAndState = useCallback19((sub) => {
|
|
10469
10522
|
cacheRef.current = { data: sub, expiresAt: Date.now() + CACHE_TTL_MS2 };
|
|
10470
10523
|
setSubscription(sub);
|
|
10471
10524
|
}, []);
|
|
10472
|
-
const invalidateCache =
|
|
10525
|
+
const invalidateCache = useCallback19(() => {
|
|
10473
10526
|
cacheRef.current = null;
|
|
10474
10527
|
const distinctId = PaywalloClient.getDistinctId();
|
|
10475
10528
|
if (distinctId) void subscriptionCache.invalidate(distinctId);
|
|
10476
10529
|
}, []);
|
|
10477
|
-
const fetchAndCache =
|
|
10530
|
+
const fetchAndCache = useCallback19(async () => {
|
|
10478
10531
|
const apiClient = PaywalloClient.getApiClient();
|
|
10479
10532
|
const distinctId = PaywalloClient.getDistinctId();
|
|
10480
10533
|
if (!apiClient || !distinctId) return null;
|
|
@@ -10484,7 +10537,7 @@ function useSubscriptionSync() {
|
|
|
10484
10537
|
void subscriptionCache.set(distinctId, toDomainResponse(status));
|
|
10485
10538
|
return sub;
|
|
10486
10539
|
}, [setCacheAndState]);
|
|
10487
|
-
const hasActiveSubscription =
|
|
10540
|
+
const hasActiveSubscription = useCallback19(async () => {
|
|
10488
10541
|
const apiClient = PaywalloClient.getApiClient();
|
|
10489
10542
|
const distinctId = PaywalloClient.getDistinctId();
|
|
10490
10543
|
if (!apiClient || !distinctId) return false;
|
|
@@ -10504,7 +10557,7 @@ function useSubscriptionSync() {
|
|
|
10504
10557
|
return resolveOfflineFromCache(distinctId);
|
|
10505
10558
|
}
|
|
10506
10559
|
}, [setCacheAndState]);
|
|
10507
|
-
const getSubscription =
|
|
10560
|
+
const getSubscription = useCallback19(async () => {
|
|
10508
10561
|
const apiClient = PaywalloClient.getApiClient();
|
|
10509
10562
|
const distinctId = PaywalloClient.getDistinctId();
|
|
10510
10563
|
if (!apiClient || !distinctId) return null;
|
|
@@ -10536,12 +10589,12 @@ function PaywalloProvider({ children, config }) {
|
|
|
10536
10589
|
const { products, isLoadingProducts, refreshProducts } = useProductLoader();
|
|
10537
10590
|
const { subscription, hasActiveSubscription, getSubscription, invalidateCache } = useSubscriptionSync();
|
|
10538
10591
|
const { preloadedWebView, setPreloadedWebView, preloadCampaign, consumePreloadedCampaign, isPreloadValid } = useCampaignPreload();
|
|
10539
|
-
const clearPreloadedWebView =
|
|
10540
|
-
const autoPreloadTriggeredRef =
|
|
10541
|
-
const preloadedWebViewRef =
|
|
10542
|
-
const pollTimerRef =
|
|
10543
|
-
const pollCancelledRef =
|
|
10544
|
-
const secureStorageRef =
|
|
10592
|
+
const clearPreloadedWebView = useCallback20(() => setPreloadedWebView(null), [setPreloadedWebView]);
|
|
10593
|
+
const autoPreloadTriggeredRef = useRef12(false);
|
|
10594
|
+
const preloadedWebViewRef = useRef12(preloadedWebView);
|
|
10595
|
+
const pollTimerRef = useRef12(null);
|
|
10596
|
+
const pollCancelledRef = useRef12(false);
|
|
10597
|
+
const secureStorageRef = useRef12(new SecureStorage(config.debug));
|
|
10545
10598
|
useEffect14(() => {
|
|
10546
10599
|
preloadedWebViewRef.current = preloadedWebView;
|
|
10547
10600
|
}, [preloadedWebView]);
|
|
@@ -10568,20 +10621,20 @@ function PaywalloProvider({ children, config }) {
|
|
|
10568
10621
|
},
|
|
10569
10622
|
debug: config.debug
|
|
10570
10623
|
});
|
|
10571
|
-
const triggerRepreload =
|
|
10624
|
+
const triggerRepreload = useCallback20((placement) => {
|
|
10572
10625
|
void PaywalloClient.preloadCampaign(placement).catch(() => {
|
|
10573
10626
|
});
|
|
10574
10627
|
}, []);
|
|
10575
10628
|
const { showingPreloadedWebView, presentPreloadedWebView, resolvePreloadedPaywall, handlePreloadedWebViewReady: baseHandlePreloadedWebViewReady, handlePreloadedClose: baseHandlePreloadedClose, setShowingPreloadedWebView, presentedAtRef } = usePaywallPresenter(preloadedWebView, setPreloadedWebView);
|
|
10576
10629
|
const SCREEN_HEIGHT = useMemo3(() => Dimensions5.get("window").height, []);
|
|
10577
|
-
const slideAnim =
|
|
10578
|
-
const handlePreloadedWebViewReady =
|
|
10630
|
+
const slideAnim = useRef12(new Animated4.Value(SCREEN_HEIGHT)).current;
|
|
10631
|
+
const handlePreloadedWebViewReady = useCallback20(() => {
|
|
10579
10632
|
if (PaywalloClient.getConfig()?.debug) {
|
|
10580
10633
|
console.log(`[Paywallo WEBVIEW] loaded \u2014 placement: ${preloadedWebView?.placement}`);
|
|
10581
10634
|
}
|
|
10582
10635
|
baseHandlePreloadedWebViewReady();
|
|
10583
10636
|
}, [preloadedWebView?.placement, baseHandlePreloadedWebViewReady]);
|
|
10584
|
-
const handlePreloadedClose =
|
|
10637
|
+
const handlePreloadedClose = useCallback20(() => {
|
|
10585
10638
|
const placement = preloadedWebView?.placement;
|
|
10586
10639
|
Animated4.timing(slideAnim, { toValue: SCREEN_HEIGHT, duration: 200, easing: Easing2.in(Easing2.cubic), useNativeDriver: true }).start(() => {
|
|
10587
10640
|
baseHandlePreloadedClose();
|
|
@@ -10597,7 +10650,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10597
10650
|
invalidateCache
|
|
10598
10651
|
);
|
|
10599
10652
|
const [isPreloadPurchasing, setIsPreloadPurchasing] = useState17(false);
|
|
10600
|
-
const handlePreloadedPurchase =
|
|
10653
|
+
const handlePreloadedPurchase = useCallback20(async (productId) => {
|
|
10601
10654
|
setIsPreloadPurchasing(true);
|
|
10602
10655
|
try {
|
|
10603
10656
|
await rawPreloadedPurchase(productId);
|
|
@@ -10605,15 +10658,25 @@ function PaywalloProvider({ children, config }) {
|
|
|
10605
10658
|
setIsPreloadPurchasing(false);
|
|
10606
10659
|
}
|
|
10607
10660
|
}, [rawPreloadedPurchase]);
|
|
10608
|
-
const configRef =
|
|
10661
|
+
const configRef = useRef12(config);
|
|
10609
10662
|
useEffect14(() => {
|
|
10610
10663
|
let mounted = true;
|
|
10611
|
-
|
|
10612
|
-
|
|
10664
|
+
const bootstrap = async () => {
|
|
10665
|
+
if (!PaywalloClient.isReady()) {
|
|
10666
|
+
initLocalization({ detectDevice: true });
|
|
10667
|
+
try {
|
|
10668
|
+
await PaywalloClient.init(configRef.current);
|
|
10669
|
+
} catch (err) {
|
|
10670
|
+
if (!mounted) return;
|
|
10671
|
+
setInitError(err instanceof Error ? err : new ClientError(CLIENT_ERROR_CODES.NOT_INITIALIZED, String(err)));
|
|
10672
|
+
return;
|
|
10673
|
+
}
|
|
10674
|
+
if (!mounted) return;
|
|
10675
|
+
startSuperwallAutoBridge(configRef.current.debug);
|
|
10676
|
+
void pushAttributionToSuperwall(configRef.current.debug);
|
|
10677
|
+
}
|
|
10613
10678
|
if (!mounted) return;
|
|
10614
10679
|
setDistinctId(PaywalloClient.getDistinctId());
|
|
10615
|
-
startSuperwallAutoBridge(configRef.current.debug);
|
|
10616
|
-
void pushAttributionToSuperwall(configRef.current.debug);
|
|
10617
10680
|
setIsInitialized(true);
|
|
10618
10681
|
if (!autoPreloadTriggeredRef.current) {
|
|
10619
10682
|
autoPreloadTriggeredRef.current = true;
|
|
@@ -10626,19 +10689,17 @@ function PaywalloProvider({ children, config }) {
|
|
|
10626
10689
|
});
|
|
10627
10690
|
}
|
|
10628
10691
|
}
|
|
10629
|
-
}
|
|
10630
|
-
|
|
10631
|
-
setInitError(err instanceof Error ? err : new ClientError(CLIENT_ERROR_CODES.NOT_INITIALIZED, String(err)));
|
|
10632
|
-
});
|
|
10692
|
+
};
|
|
10693
|
+
void bootstrap();
|
|
10633
10694
|
return () => {
|
|
10634
10695
|
mounted = false;
|
|
10635
10696
|
};
|
|
10636
10697
|
}, [preloadCampaign]);
|
|
10637
|
-
const getPaywallConfig =
|
|
10698
|
+
const getPaywallConfig = useCallback20(async (p) => {
|
|
10638
10699
|
const api = PaywalloClient.getApiClient();
|
|
10639
10700
|
return api ? api.getPaywall(p) : null;
|
|
10640
10701
|
}, []);
|
|
10641
|
-
const presentPaywall =
|
|
10702
|
+
const presentPaywall = useCallback20((placement) => {
|
|
10642
10703
|
const preloaded = paywallPreloadService.getPreloaded(placement);
|
|
10643
10704
|
return new Promise((resolve) => setActivePaywall({
|
|
10644
10705
|
placement,
|
|
@@ -10656,7 +10717,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10656
10717
|
}
|
|
10657
10718
|
}));
|
|
10658
10719
|
}, []);
|
|
10659
|
-
const trackCampaignImpression =
|
|
10720
|
+
const trackCampaignImpression = useCallback20((placement, variantKey, campaignId) => {
|
|
10660
10721
|
const api = PaywalloClient.getApiClient();
|
|
10661
10722
|
if (!api) return;
|
|
10662
10723
|
const sessionId = PaywalloClient.getSessionId();
|
|
@@ -10670,7 +10731,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10670
10731
|
}).catch(() => {
|
|
10671
10732
|
});
|
|
10672
10733
|
}, []);
|
|
10673
|
-
const presentCampaign =
|
|
10734
|
+
const presentCampaign = useCallback20(
|
|
10674
10735
|
async (placement, context) => {
|
|
10675
10736
|
try {
|
|
10676
10737
|
if (preloadedWebView?.placement === placement && preloadedWebView.loaded && isPreloadValid(placement)) {
|
|
@@ -10744,7 +10805,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10744
10805
|
},
|
|
10745
10806
|
[preloadedWebView, isPreloadValid, consumePreloadedCampaign, presentPreloadedWebView, trackCampaignImpression]
|
|
10746
10807
|
);
|
|
10747
|
-
const restorePurchases =
|
|
10808
|
+
const restorePurchases = useCallback20(async () => {
|
|
10748
10809
|
invalidateCache();
|
|
10749
10810
|
try {
|
|
10750
10811
|
const txs = await getIAPService().restore();
|
|
@@ -10753,13 +10814,13 @@ function PaywalloProvider({ children, config }) {
|
|
|
10753
10814
|
return { success: false, restoredProducts: [], error: error instanceof Error ? error : new PurchaseError(PURCHASE_ERROR_CODES.RESTORE_FAILED, String(error)) };
|
|
10754
10815
|
}
|
|
10755
10816
|
}, [invalidateCache]);
|
|
10756
|
-
const handlePaywallResult =
|
|
10817
|
+
const handlePaywallResult = useCallback20((result) => {
|
|
10757
10818
|
if (activePaywall) {
|
|
10758
10819
|
activePaywall.resolver(result);
|
|
10759
10820
|
setActivePaywall(null);
|
|
10760
10821
|
}
|
|
10761
10822
|
}, [activePaywall]);
|
|
10762
|
-
const bridgePaywallPresenter =
|
|
10823
|
+
const bridgePaywallPresenter = useCallback20((placement) => {
|
|
10763
10824
|
if (PaywalloClient.getConfig()?.debug) {
|
|
10764
10825
|
console.log(`[Paywallo PRESENT] called \u2014 preloaded: ${preloadedWebViewRef.current?.loaded === true} placement: ${placement}`);
|
|
10765
10826
|
}
|
|
@@ -10815,7 +10876,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10815
10876
|
};
|
|
10816
10877
|
}, [isInitialized, bridgePaywallPresenter, getSubscription, hasActiveSubscription, restorePurchases]);
|
|
10817
10878
|
const isReady = isInitialized && !isLoadingProducts;
|
|
10818
|
-
const noOp =
|
|
10879
|
+
const noOp = useCallback20(() => {
|
|
10819
10880
|
}, []);
|
|
10820
10881
|
const contextValue = useMemo3(() => ({
|
|
10821
10882
|
config: PaywalloClient.getConfig(),
|
|
@@ -11070,6 +11131,7 @@ export {
|
|
|
11070
11131
|
createPurchaseError,
|
|
11071
11132
|
index_default as default,
|
|
11072
11133
|
detectDeviceLanguage,
|
|
11134
|
+
getActiveRouteName,
|
|
11073
11135
|
getCurrentLanguage,
|
|
11074
11136
|
getDefaultLanguage,
|
|
11075
11137
|
getIAPService,
|
|
@@ -11098,6 +11160,7 @@ export {
|
|
|
11098
11160
|
useOnboarding,
|
|
11099
11161
|
usePaywallContext,
|
|
11100
11162
|
usePaywallo,
|
|
11163
|
+
usePaywalloScreenTracking,
|
|
11101
11164
|
usePlanPurchase,
|
|
11102
11165
|
usePlans,
|
|
11103
11166
|
useProducts,
|