@virex-tech/paywallo-sdk 2.2.7 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +210 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +210 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -412,11 +412,28 @@ function parseProperties(json) {
|
|
|
412
412
|
return {};
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
|
-
|
|
415
|
+
async function persistAnonIdDurably(storage, anonId) {
|
|
416
|
+
let stored = await storage.set(ANON_ID_KEY, anonId);
|
|
417
|
+
for (let i = 0; i < ANON_ID_SET_RETRIES && !stored; i++) {
|
|
418
|
+
await new Promise((r) => setTimeout(r, ANON_ID_RETRY_DELAY_MS));
|
|
419
|
+
stored = await storage.set(ANON_ID_KEY, anonId);
|
|
420
|
+
}
|
|
421
|
+
if (!stored) {
|
|
422
|
+
await nativeStorage.set(ANON_ID_FALLBACK_KEY, anonId).catch(() => void 0);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async function readAnonIdDurably(storage) {
|
|
426
|
+
const secure = await readWithMigration(storage, ANON_ID_KEY, LEGACY_ANON_ID_KEY);
|
|
427
|
+
if (secure) return secure;
|
|
428
|
+
return nativeStorage.get(ANON_ID_FALLBACK_KEY);
|
|
429
|
+
}
|
|
430
|
+
var DEVICE_ID_KEY, ANON_ID_FALLBACK_KEY, ANON_ID_KEY, USER_EMAIL_KEY, USER_PROPERTIES_KEY, USER_DISTINCT_ID_KEY, USER_NAME_KEY, USER_COUNTRY_KEY, USER_LOCALE_KEY, USER_PHONE_KEY, USER_FIRST_NAME_KEY, USER_LAST_NAME_KEY, USER_DOB_KEY, USER_GENDER_KEY, LEGACY_USER_PHONE_KEY, LEGACY_USER_FIRST_NAME_KEY, LEGACY_USER_LAST_NAME_KEY, LEGACY_USER_DOB_KEY, LEGACY_USER_GENDER_KEY, LEGACY_DEVICE_ID_KEY, LEGACY_ANON_ID_KEY, LEGACY_EMAIL_KEY, LEGACY_PROPERTIES_KEY, LEGACY_DISTINCT_ID_KEY, LEGACY_NAME_KEY, LEGACY_COUNTRY_KEY, LEGACY_LOCALE_KEY, ANON_ID_SET_RETRIES, ANON_ID_RETRY_DELAY_MS;
|
|
416
431
|
var init_IdentityStorage = __esm({
|
|
417
432
|
"src/domains/identity/IdentityStorage.ts"() {
|
|
418
433
|
"use strict";
|
|
434
|
+
init_NativeStorage();
|
|
419
435
|
DEVICE_ID_KEY = "@paywallo:device_id";
|
|
436
|
+
ANON_ID_FALLBACK_KEY = "@paywallo:anon_id_fallback";
|
|
420
437
|
ANON_ID_KEY = "@paywallo:anon_id";
|
|
421
438
|
USER_EMAIL_KEY = "@paywallo:user_email";
|
|
422
439
|
USER_PROPERTIES_KEY = "@paywallo:user_properties";
|
|
@@ -442,6 +459,8 @@ var init_IdentityStorage = __esm({
|
|
|
442
459
|
LEGACY_NAME_KEY = "user_name";
|
|
443
460
|
LEGACY_COUNTRY_KEY = "user_country";
|
|
444
461
|
LEGACY_LOCALE_KEY = "user_locale";
|
|
462
|
+
ANON_ID_SET_RETRIES = 2;
|
|
463
|
+
ANON_ID_RETRY_DELAY_MS = 50;
|
|
445
464
|
}
|
|
446
465
|
});
|
|
447
466
|
|
|
@@ -521,8 +540,7 @@ var init_IdentityManager = __esm({
|
|
|
521
540
|
}
|
|
522
541
|
if (!this.anonId) {
|
|
523
542
|
this.anonId = generateUUID();
|
|
524
|
-
await this.secureStorage
|
|
525
|
-
});
|
|
543
|
+
await persistAnonIdDurably(this.secureStorage, this.anonId);
|
|
526
544
|
}
|
|
527
545
|
this.initialized = true;
|
|
528
546
|
return this.deviceId ?? "";
|
|
@@ -582,7 +600,8 @@ var init_IdentityManager = __esm({
|
|
|
582
600
|
dateOfBirth: this.dateOfBirth ?? void 0,
|
|
583
601
|
gender: this.gender ?? void 0
|
|
584
602
|
});
|
|
585
|
-
} catch {
|
|
603
|
+
} catch (err) {
|
|
604
|
+
if (this.debug) console.log("[Paywallo] identify dispatch error", err);
|
|
586
605
|
}
|
|
587
606
|
}
|
|
588
607
|
}
|
|
@@ -606,7 +625,8 @@ var init_IdentityManager = __esm({
|
|
|
606
625
|
if (this.apiClient && this.anonId) {
|
|
607
626
|
try {
|
|
608
627
|
await this.apiClient.identify(this.anonId, this.properties, this.email ?? void 0, this.deviceId ?? void 0);
|
|
609
|
-
} catch {
|
|
628
|
+
} catch (err) {
|
|
629
|
+
if (this.debug) console.log("[Paywallo] identify dispatch error", err);
|
|
610
630
|
}
|
|
611
631
|
}
|
|
612
632
|
}
|
|
@@ -649,18 +669,20 @@ var init_IdentityManager = __esm({
|
|
|
649
669
|
}
|
|
650
670
|
async loadPersistedState() {
|
|
651
671
|
if (!this.secureStorage) return;
|
|
652
|
-
const state = await
|
|
672
|
+
const [state, rawAnonId] = await Promise.all([
|
|
673
|
+
loadPersistedIdentity(this.secureStorage),
|
|
674
|
+
readAnonIdDurably(this.secureStorage)
|
|
675
|
+
]);
|
|
653
676
|
const deviceId = state.deviceId ?? await readDeviceIdWithFallback(this.secureStorage);
|
|
654
677
|
if (deviceId) this.deviceId = deviceId;
|
|
655
|
-
if (
|
|
678
|
+
if (rawAnonId) {
|
|
656
679
|
const legacyPrefix = "$paywallo_anon:";
|
|
657
|
-
if (
|
|
658
|
-
const stripped =
|
|
680
|
+
if (rawAnonId.startsWith(legacyPrefix)) {
|
|
681
|
+
const stripped = rawAnonId.slice(legacyPrefix.length);
|
|
659
682
|
this.anonId = stripped;
|
|
660
|
-
await this.secureStorage.set(ANON_ID_KEY, stripped).catch(() =>
|
|
661
|
-
});
|
|
683
|
+
await this.secureStorage.set(ANON_ID_KEY, stripped).catch(() => void 0);
|
|
662
684
|
} else {
|
|
663
|
-
this.anonId =
|
|
685
|
+
this.anonId = rawAnonId;
|
|
664
686
|
}
|
|
665
687
|
}
|
|
666
688
|
if (state.email) this.email = state.email;
|
|
@@ -885,21 +907,23 @@ var init_AdvertisingIdManager = __esm({
|
|
|
885
907
|
if (Platform.OS === "ios") {
|
|
886
908
|
if (!tracking.isAvailable()) {
|
|
887
909
|
const idfv2 = await this.collectIdfv();
|
|
888
|
-
|
|
889
|
-
|
|
910
|
+
const result2 = { ...fallback, idfv: idfv2 };
|
|
911
|
+
if (idfv2 !== null) this.cached = result2;
|
|
912
|
+
return result2;
|
|
890
913
|
}
|
|
891
914
|
const current = await tracking.getTrackingPermissionsAsync();
|
|
892
915
|
let status = current.status;
|
|
893
916
|
let granted = current.granted;
|
|
894
917
|
if (status === "undetermined" && requestATT) {
|
|
895
|
-
const
|
|
896
|
-
status =
|
|
897
|
-
granted =
|
|
918
|
+
const result2 = await tracking.requestTrackingPermissionsAsync();
|
|
919
|
+
status = result2.status;
|
|
920
|
+
granted = result2.granted;
|
|
898
921
|
}
|
|
899
922
|
const idfv = await this.collectIdfv();
|
|
900
923
|
const idfa = granted ? this.sanitizeId(tracking.getAdvertisingId()) : null;
|
|
901
|
-
|
|
902
|
-
|
|
924
|
+
const result = { idfv, idfa, gaid: null, attStatus: status };
|
|
925
|
+
if (idfv !== null) this.cached = result;
|
|
926
|
+
return result;
|
|
903
927
|
}
|
|
904
928
|
if (Platform.OS === "android") {
|
|
905
929
|
const rawGaid = tracking.getAdvertisingId();
|
|
@@ -915,12 +939,20 @@ var init_AdvertisingIdManager = __esm({
|
|
|
915
939
|
}
|
|
916
940
|
}
|
|
917
941
|
async collectIdfv() {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
942
|
+
const RETRY_DELAY_MS = 80;
|
|
943
|
+
const MAX_ATTEMPTS = 3;
|
|
944
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
945
|
+
try {
|
|
946
|
+
const info = await nativeDeviceInfo.getDeviceInfo();
|
|
947
|
+
const idfv = this.sanitizeId(info.idfv);
|
|
948
|
+
if (idfv !== null) return idfv;
|
|
949
|
+
} catch {
|
|
950
|
+
}
|
|
951
|
+
if (attempt < MAX_ATTEMPTS - 1) {
|
|
952
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
953
|
+
}
|
|
923
954
|
}
|
|
955
|
+
return null;
|
|
924
956
|
}
|
|
925
957
|
sanitizeId(id) {
|
|
926
958
|
if (!id || id === ZERO_IDFA) return null;
|
|
@@ -1358,6 +1390,8 @@ var init_AttributionTracker = __esm({
|
|
|
1358
1390
|
|
|
1359
1391
|
// src/domains/identity/InstallIdempotency.ts
|
|
1360
1392
|
async function checkAndArmInstallGuard(storage) {
|
|
1393
|
+
if (armedThisLaunch) return true;
|
|
1394
|
+
armedThisLaunch = true;
|
|
1361
1395
|
const alreadyTracked = await storage.get(INSTALL_KEYS.INSTALL_TRACKED);
|
|
1362
1396
|
if (alreadyTracked) return true;
|
|
1363
1397
|
let fallbackTracked = null;
|
|
@@ -1391,7 +1425,7 @@ async function getOrCreateInstallEventId() {
|
|
|
1391
1425
|
});
|
|
1392
1426
|
return id;
|
|
1393
1427
|
}
|
|
1394
|
-
var INSTALL_KEYS;
|
|
1428
|
+
var INSTALL_KEYS, armedThisLaunch;
|
|
1395
1429
|
var init_InstallIdempotency = __esm({
|
|
1396
1430
|
"src/domains/identity/InstallIdempotency.ts"() {
|
|
1397
1431
|
"use strict";
|
|
@@ -1416,6 +1450,7 @@ var init_InstallIdempotency = __esm({
|
|
|
1416
1450
|
/** Legacy anon ID key written by SDK versions that used @panel: prefix. */
|
|
1417
1451
|
LEGACY_ANON_ID: "@panel:anon_id"
|
|
1418
1452
|
};
|
|
1453
|
+
armedThisLaunch = false;
|
|
1419
1454
|
}
|
|
1420
1455
|
});
|
|
1421
1456
|
|
|
@@ -2370,8 +2405,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2370
2405
|
// src/core/version.ts
|
|
2371
2406
|
function resolveVersion() {
|
|
2372
2407
|
try {
|
|
2373
|
-
if ("2.
|
|
2374
|
-
return "2.
|
|
2408
|
+
if ("2.4.0") {
|
|
2409
|
+
return "2.4.0";
|
|
2375
2410
|
}
|
|
2376
2411
|
} catch {
|
|
2377
2412
|
}
|
|
@@ -3387,6 +3422,7 @@ function buildPaywallInjectionScript(data) {
|
|
|
3387
3422
|
products: data.products,
|
|
3388
3423
|
primaryProductId: data.primaryProductId,
|
|
3389
3424
|
secondaryProductId: data.secondaryProductId,
|
|
3425
|
+
tertiaryProductId: data.tertiaryProductId,
|
|
3390
3426
|
currentLanguage: getCurrentLanguage(),
|
|
3391
3427
|
defaultLanguage: getDefaultLanguage()
|
|
3392
3428
|
}
|
|
@@ -3485,6 +3521,7 @@ function PaywallWebView({
|
|
|
3485
3521
|
products,
|
|
3486
3522
|
primaryProductId,
|
|
3487
3523
|
secondaryProductId,
|
|
3524
|
+
tertiaryProductId,
|
|
3488
3525
|
isPurchasing,
|
|
3489
3526
|
webUrl: webUrlProp,
|
|
3490
3527
|
onPurchase,
|
|
@@ -3556,10 +3593,11 @@ function PaywallWebView({
|
|
|
3556
3593
|
craftData,
|
|
3557
3594
|
products: Array.from(products.values()),
|
|
3558
3595
|
primaryProductId,
|
|
3559
|
-
secondaryProductId
|
|
3596
|
+
secondaryProductId,
|
|
3597
|
+
tertiaryProductId
|
|
3560
3598
|
});
|
|
3561
3599
|
injectScript(script);
|
|
3562
|
-
}, [craftData, products, primaryProductId, secondaryProductId, injectScript]);
|
|
3600
|
+
}, [craftData, products, primaryProductId, secondaryProductId, tertiaryProductId, injectScript]);
|
|
3563
3601
|
const processedIdsRef = useRef2(/* @__PURE__ */ new Set());
|
|
3564
3602
|
const dedupeTimersRef = useRef2(/* @__PURE__ */ new Map());
|
|
3565
3603
|
useEffect2(() => {
|
|
@@ -4241,10 +4279,10 @@ var init_OfflineQueueStorage = __esm({
|
|
|
4241
4279
|
init_NativeStorage();
|
|
4242
4280
|
init_QueueJournal();
|
|
4243
4281
|
OfflineQueueStorage = class {
|
|
4244
|
-
constructor(config, emit,
|
|
4282
|
+
constructor(config, emit, log3) {
|
|
4245
4283
|
this.config = config;
|
|
4246
4284
|
this.emit = emit;
|
|
4247
|
-
this.log =
|
|
4285
|
+
this.log = log3;
|
|
4248
4286
|
}
|
|
4249
4287
|
async loadFromStorage(queue) {
|
|
4250
4288
|
const { merged, recovered, hadJournal } = await mergeJournalIntoMain(
|
|
@@ -5502,7 +5540,8 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
5502
5540
|
placement: snap.placement,
|
|
5503
5541
|
config: snap.config,
|
|
5504
5542
|
primaryProductId: snap.primaryProductId,
|
|
5505
|
-
secondaryProductId: snap.secondaryProductId
|
|
5543
|
+
secondaryProductId: snap.secondaryProductId,
|
|
5544
|
+
tertiaryProductId: snap.tertiaryProductId
|
|
5506
5545
|
};
|
|
5507
5546
|
} else {
|
|
5508
5547
|
const fetched = await apiClient.getPaywall(placement);
|
|
@@ -5514,6 +5553,7 @@ function usePaywallLoader(placement, visible, preloadedConfig, preloadedProducts
|
|
|
5514
5553
|
const productIds = [];
|
|
5515
5554
|
if (config.primaryProductId) productIds.push(config.primaryProductId);
|
|
5516
5555
|
if (config.secondaryProductId) productIds.push(config.secondaryProductId);
|
|
5556
|
+
if (config.tertiaryProductId) productIds.push(config.tertiaryProductId);
|
|
5517
5557
|
const snapProducts = preloadedProductsRef.current;
|
|
5518
5558
|
if (snapProducts && snapProducts.size > 0) {
|
|
5519
5559
|
if (!cancelled) setProducts(snapProducts);
|
|
@@ -5707,6 +5747,7 @@ function PaywallModal({
|
|
|
5707
5747
|
products,
|
|
5708
5748
|
primaryProductId: paywallConfig.primaryProductId,
|
|
5709
5749
|
secondaryProductId: paywallConfig.secondaryProductId,
|
|
5750
|
+
tertiaryProductId: paywallConfig.tertiaryProductId,
|
|
5710
5751
|
isPurchasing,
|
|
5711
5752
|
onReady: handleWebViewReady,
|
|
5712
5753
|
onClose: handleClose,
|
|
@@ -5885,6 +5926,7 @@ var init_PaywallPreloadService = __esm({
|
|
|
5885
5926
|
const productIds = [];
|
|
5886
5927
|
if (config.primaryProductId) productIds.push(config.primaryProductId);
|
|
5887
5928
|
if (config.secondaryProductId) productIds.push(config.secondaryProductId);
|
|
5929
|
+
if (config.tertiaryProductId) productIds.push(config.tertiaryProductId);
|
|
5888
5930
|
if (productIds.length === 0) return /* @__PURE__ */ new Map();
|
|
5889
5931
|
try {
|
|
5890
5932
|
const loaded = await getIAPService().loadProducts(productIds);
|
|
@@ -7931,7 +7973,36 @@ var init_http = __esm({
|
|
|
7931
7973
|
|
|
7932
7974
|
// src/core/ApiClient.ts
|
|
7933
7975
|
import { Platform as Platform15 } from "react-native";
|
|
7934
|
-
|
|
7976
|
+
function normalizeDateOfBirth(raw) {
|
|
7977
|
+
if (!raw) return void 0;
|
|
7978
|
+
if (DATE_OF_BIRTH_RE.test(raw)) return raw;
|
|
7979
|
+
const d = new Date(raw);
|
|
7980
|
+
if (isNaN(d.getTime())) return void 0;
|
|
7981
|
+
const hasTimeComponent = raw.includes("T") || raw.includes("Z");
|
|
7982
|
+
const yyyy = hasTimeComponent ? d.getUTCFullYear() : d.getFullYear();
|
|
7983
|
+
const mm = String((hasTimeComponent ? d.getUTCMonth() : d.getMonth()) + 1).padStart(2, "0");
|
|
7984
|
+
const dd = String(hasTimeComponent ? d.getUTCDate() : d.getDate()).padStart(2, "0");
|
|
7985
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
7986
|
+
}
|
|
7987
|
+
function buildPiiPayload(pii) {
|
|
7988
|
+
const result = {};
|
|
7989
|
+
if (pii.phone) result.phone = pii.phone;
|
|
7990
|
+
if (pii.firstName) result.firstName = pii.firstName;
|
|
7991
|
+
if (pii.lastName) result.lastName = pii.lastName;
|
|
7992
|
+
const dob = normalizeDateOfBirth(pii.dateOfBirth);
|
|
7993
|
+
if (dob) result.dateOfBirth = dob;
|
|
7994
|
+
const g = normalizeGender(pii.gender);
|
|
7995
|
+
if (g) result.gender = g;
|
|
7996
|
+
return result;
|
|
7997
|
+
}
|
|
7998
|
+
function normalizeGender(raw) {
|
|
7999
|
+
if (!raw) return void 0;
|
|
8000
|
+
const lower = raw.toLowerCase();
|
|
8001
|
+
if (lower === "m" || lower === "male") return "m";
|
|
8002
|
+
if (lower === "f" || lower === "female") return "f";
|
|
8003
|
+
return void 0;
|
|
8004
|
+
}
|
|
8005
|
+
var DATE_OF_BIRTH_RE, ApiClient;
|
|
7935
8006
|
var init_ApiClient = __esm({
|
|
7936
8007
|
"src/core/ApiClient.ts"() {
|
|
7937
8008
|
"use strict";
|
|
@@ -7944,6 +8015,7 @@ var init_ApiClient = __esm({
|
|
|
7944
8015
|
init_http();
|
|
7945
8016
|
init_queue();
|
|
7946
8017
|
init_version();
|
|
8018
|
+
DATE_OF_BIRTH_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
7947
8019
|
ApiClient = class {
|
|
7948
8020
|
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
7949
8021
|
this.cache = new ApiCache();
|
|
@@ -8102,6 +8174,8 @@ var init_ApiClient = __esm({
|
|
|
8102
8174
|
}
|
|
8103
8175
|
}
|
|
8104
8176
|
const attribution = Object.keys(rawAttribution).length > 0 ? rawAttribution : void 0;
|
|
8177
|
+
const rawUserId = properties?.["userId"];
|
|
8178
|
+
const externalUserId = typeof rawUserId === "string" && rawUserId.length > 0 ? rawUserId : void 0;
|
|
8105
8179
|
await postWithQueue(
|
|
8106
8180
|
{
|
|
8107
8181
|
isOfflineQueueEnabled: () => this.offlineQueueEnabled,
|
|
@@ -8112,14 +8186,11 @@ var init_ApiClient = __esm({
|
|
|
8112
8186
|
"/sdk/identity/identify",
|
|
8113
8187
|
{
|
|
8114
8188
|
distinct_id: distinctId,
|
|
8189
|
+
...externalUserId && { external_user_id: externalUserId },
|
|
8115
8190
|
traits,
|
|
8116
8191
|
...attribution && { attribution },
|
|
8117
8192
|
...deviceId && { deviceId },
|
|
8118
|
-
...pii
|
|
8119
|
-
...pii?.firstName && { firstName: pii.firstName },
|
|
8120
|
-
...pii?.lastName && { lastName: pii.lastName },
|
|
8121
|
-
...pii?.dateOfBirth && { dateOfBirth: pii.dateOfBirth },
|
|
8122
|
-
...pii?.gender && { gender: pii.gender }
|
|
8193
|
+
...pii ? buildPiiPayload(pii) : {}
|
|
8123
8194
|
},
|
|
8124
8195
|
"identify"
|
|
8125
8196
|
);
|
|
@@ -9681,6 +9752,88 @@ init_paywall();
|
|
|
9681
9752
|
init_paywall();
|
|
9682
9753
|
init_paywall();
|
|
9683
9754
|
|
|
9755
|
+
// src/domains/paywall/SuperwallAttributeBridge.ts
|
|
9756
|
+
init_identity();
|
|
9757
|
+
var lastSignature = null;
|
|
9758
|
+
function log(debug, msg, data) {
|
|
9759
|
+
if (!debug) return;
|
|
9760
|
+
if (data !== void 0) console.log(`[Paywallo:SuperwallAttr] ${msg}`, data);
|
|
9761
|
+
else console.log(`[Paywallo:SuperwallAttr] ${msg}`);
|
|
9762
|
+
}
|
|
9763
|
+
var PAID_MEDIUM = /cpc|ppc|cpm|cpa|paid|display/i;
|
|
9764
|
+
function deriveIsPaid(a) {
|
|
9765
|
+
if (a.fbclid || a.gclid || a.ttclid || a.tiktokCampaignId) return true;
|
|
9766
|
+
return Boolean(a.utmMedium && PAID_MEDIUM.test(a.utmMedium));
|
|
9767
|
+
}
|
|
9768
|
+
function deriveAdNetwork(a) {
|
|
9769
|
+
if (a.fbclid) return "meta";
|
|
9770
|
+
if (a.ttclid || a.tiktokCampaignId) return "tiktok";
|
|
9771
|
+
if (a.gclid) return "google";
|
|
9772
|
+
return a.utmSource;
|
|
9773
|
+
}
|
|
9774
|
+
function buildSuperwallAttributes(a) {
|
|
9775
|
+
const out = {};
|
|
9776
|
+
if (!a) {
|
|
9777
|
+
out.pw_is_paid = false;
|
|
9778
|
+
return out;
|
|
9779
|
+
}
|
|
9780
|
+
const set2 = (key, value) => {
|
|
9781
|
+
if (value) out[key] = value;
|
|
9782
|
+
};
|
|
9783
|
+
set2("pw_utm_source", a.utmSource);
|
|
9784
|
+
set2("pw_utm_medium", a.utmMedium);
|
|
9785
|
+
set2("pw_utm_campaign", a.utmCampaign);
|
|
9786
|
+
set2("pw_utm_content", a.utmContent);
|
|
9787
|
+
set2("pw_utm_term", a.utmTerm);
|
|
9788
|
+
set2("pw_fbclid", a.fbclid);
|
|
9789
|
+
set2("pw_gclid", a.gclid);
|
|
9790
|
+
set2("pw_ttclid", a.ttclid);
|
|
9791
|
+
set2("pw_tiktok_campaign_id", a.tiktokCampaignId);
|
|
9792
|
+
set2("pw_tiktok_adgroup_id", a.tiktokAdgroupId);
|
|
9793
|
+
set2("pw_tiktok_ad_id", a.tiktokAdId);
|
|
9794
|
+
set2("pw_referrer", a.referrer);
|
|
9795
|
+
set2("pw_install_referrer_source", a.installReferrerSource);
|
|
9796
|
+
set2("pw_ad_network", deriveAdNetwork(a));
|
|
9797
|
+
out.pw_is_paid = deriveIsPaid(a);
|
|
9798
|
+
out.pw_attributed_at = a.capturedAt;
|
|
9799
|
+
return out;
|
|
9800
|
+
}
|
|
9801
|
+
function pickShared(mod) {
|
|
9802
|
+
const shared = mod?.default?.shared ?? mod?.shared;
|
|
9803
|
+
return shared && typeof shared.setUserAttributes === "function" ? shared : null;
|
|
9804
|
+
}
|
|
9805
|
+
async function resolveSuperwallShared(debug) {
|
|
9806
|
+
try {
|
|
9807
|
+
const shared = pickShared(await import("expo-superwall/compat"));
|
|
9808
|
+
if (shared) return shared;
|
|
9809
|
+
} catch {
|
|
9810
|
+
}
|
|
9811
|
+
try {
|
|
9812
|
+
const shared = pickShared(await import("expo-superwall"));
|
|
9813
|
+
if (shared) return shared;
|
|
9814
|
+
} catch {
|
|
9815
|
+
}
|
|
9816
|
+
log(debug, "expo-superwall not available \u2014 attribute push skipped");
|
|
9817
|
+
return null;
|
|
9818
|
+
}
|
|
9819
|
+
async function pushAttributionToSuperwall(debug = false) {
|
|
9820
|
+
const attrs = buildSuperwallAttributes(attributionTracker.get());
|
|
9821
|
+
const signature = JSON.stringify(attrs);
|
|
9822
|
+
if (signature === lastSignature) {
|
|
9823
|
+
log(debug, "attributes unchanged \u2014 skipping push");
|
|
9824
|
+
return;
|
|
9825
|
+
}
|
|
9826
|
+
const shared = await resolveSuperwallShared(debug);
|
|
9827
|
+
if (!shared) return;
|
|
9828
|
+
try {
|
|
9829
|
+
await shared.setUserAttributes(attrs);
|
|
9830
|
+
lastSignature = signature;
|
|
9831
|
+
log(debug, "attributes pushed to Superwall", attrs);
|
|
9832
|
+
} catch (err) {
|
|
9833
|
+
log(debug, "setUserAttributes error", { err: String(err) });
|
|
9834
|
+
}
|
|
9835
|
+
}
|
|
9836
|
+
|
|
9684
9837
|
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9685
9838
|
init_PaywalloClient();
|
|
9686
9839
|
|
|
@@ -9714,7 +9867,7 @@ function buildDeterministicEventId(parts) {
|
|
|
9714
9867
|
var bridgeStarted = false;
|
|
9715
9868
|
var unsubscribe = null;
|
|
9716
9869
|
var debugEnabled = false;
|
|
9717
|
-
function
|
|
9870
|
+
function log2(msg, data) {
|
|
9718
9871
|
if (!debugEnabled) return;
|
|
9719
9872
|
if (data !== void 0) {
|
|
9720
9873
|
console.log(`[Paywallo:SuperwallBridge] ${msg}`, data);
|
|
@@ -9744,7 +9897,7 @@ async function trackPaywallEvent(type, identifier, ts, extra) {
|
|
|
9744
9897
|
}
|
|
9745
9898
|
});
|
|
9746
9899
|
} catch (err) {
|
|
9747
|
-
|
|
9900
|
+
log2("track error", { type, identifier, eventId: _eventId, err: String(err) });
|
|
9748
9901
|
}
|
|
9749
9902
|
}
|
|
9750
9903
|
function mapDismissToCloseReason(resultType) {
|
|
@@ -9764,7 +9917,7 @@ function buildCallbacks() {
|
|
|
9764
9917
|
return {
|
|
9765
9918
|
onPaywallPresent: (info) => {
|
|
9766
9919
|
const ts = Date.now();
|
|
9767
|
-
|
|
9920
|
+
log2("onPaywallPresent", { identifier: info.identifier });
|
|
9768
9921
|
void trackPaywallEvent("viewed", info.identifier, ts, {
|
|
9769
9922
|
placement: info.presentedByEventWithName,
|
|
9770
9923
|
variant_id: info.experiment?.variant?.id,
|
|
@@ -9773,7 +9926,7 @@ function buildCallbacks() {
|
|
|
9773
9926
|
},
|
|
9774
9927
|
onPaywallDismiss: (info, result) => {
|
|
9775
9928
|
const ts = Date.now();
|
|
9776
|
-
|
|
9929
|
+
log2("onPaywallDismiss", { identifier: info.identifier, result: result.type });
|
|
9777
9930
|
void trackPaywallEvent("closed", info.identifier, ts, {
|
|
9778
9931
|
placement: info.presentedByEventWithName,
|
|
9779
9932
|
variant_id: info.experiment?.variant?.id,
|
|
@@ -9787,7 +9940,7 @@ function buildCallbacks() {
|
|
|
9787
9940
|
const safe = params !== null && typeof params === "object" ? params : {};
|
|
9788
9941
|
const productId = "productId" in safe && typeof safe.productId === "string" ? safe.productId : "unknown";
|
|
9789
9942
|
const identifier = "paywallIdentifier" in safe && typeof safe.paywallIdentifier === "string" ? safe.paywallIdentifier : productId;
|
|
9790
|
-
|
|
9943
|
+
log2("onPurchase", { productId, identifier });
|
|
9791
9944
|
void trackPaywallEvent("purchased", identifier, ts, { product_id: productId });
|
|
9792
9945
|
},
|
|
9793
9946
|
// Global Superwall event listener — used specifically for `transactionComplete`
|
|
@@ -9802,7 +9955,7 @@ function buildCallbacks() {
|
|
|
9802
9955
|
const product = ev.product;
|
|
9803
9956
|
const transaction = ev.transaction;
|
|
9804
9957
|
if (!product) {
|
|
9805
|
-
|
|
9958
|
+
log2("transactionComplete missing product \u2014 skipping transaction track");
|
|
9806
9959
|
return;
|
|
9807
9960
|
}
|
|
9808
9961
|
const productId = product.productIdentifier ?? product.id ?? "unknown";
|
|
@@ -9811,7 +9964,7 @@ function buildCallbacks() {
|
|
|
9811
9964
|
const transactionId = transaction?.storeTransactionId ?? transaction?.originalTransactionIdentifier ?? `${productId}_${String(ts)}`;
|
|
9812
9965
|
const isTrial = product.hasFreeTrial === true || (product.trialPeriodPrice ?? 0) > 0;
|
|
9813
9966
|
const paywallIdentifier = ev.paywallInfo?.identifier;
|
|
9814
|
-
|
|
9967
|
+
log2("onSuperwallEvent: transactionComplete", { productId, currency, price, transactionId, isTrial });
|
|
9815
9968
|
void (async () => {
|
|
9816
9969
|
try {
|
|
9817
9970
|
await PaywalloClient.track("transaction", {
|
|
@@ -9829,7 +9982,7 @@ function buildCallbacks() {
|
|
|
9829
9982
|
}
|
|
9830
9983
|
});
|
|
9831
9984
|
} catch (err) {
|
|
9832
|
-
|
|
9985
|
+
log2("transactionComplete track error", { err: String(err) });
|
|
9833
9986
|
}
|
|
9834
9987
|
})();
|
|
9835
9988
|
}
|
|
@@ -9838,7 +9991,7 @@ function buildCallbacks() {
|
|
|
9838
9991
|
function startSuperwallAutoBridge(debug = false) {
|
|
9839
9992
|
debugEnabled = debug;
|
|
9840
9993
|
if (bridgeStarted) {
|
|
9841
|
-
|
|
9994
|
+
log2("already started, skipping");
|
|
9842
9995
|
return;
|
|
9843
9996
|
}
|
|
9844
9997
|
void detectAndStart();
|
|
@@ -9850,7 +10003,7 @@ async function detectAndStart() {
|
|
|
9850
10003
|
if (!mod || typeof mod.subscribeToSuperwallEvents !== "function") {
|
|
9851
10004
|
const internal = await import("expo-superwall/build/src/internal/superwallEventBridge");
|
|
9852
10005
|
if (typeof internal.subscribeToSuperwallEvents !== "function") {
|
|
9853
|
-
|
|
10006
|
+
log2("expo-superwall subscribeToSuperwallEvents not found \u2014 bridge inactive");
|
|
9854
10007
|
return;
|
|
9855
10008
|
}
|
|
9856
10009
|
subscribeFn = internal.subscribeToSuperwallEvents;
|
|
@@ -9858,16 +10011,16 @@ async function detectAndStart() {
|
|
|
9858
10011
|
subscribeFn = mod.subscribeToSuperwallEvents;
|
|
9859
10012
|
}
|
|
9860
10013
|
} catch {
|
|
9861
|
-
|
|
10014
|
+
log2("expo-superwall not installed \u2014 bridge inactive");
|
|
9862
10015
|
return;
|
|
9863
10016
|
}
|
|
9864
10017
|
try {
|
|
9865
10018
|
const callbacks = buildCallbacks();
|
|
9866
10019
|
unsubscribe = subscribeFn(void 0, () => callbacks);
|
|
9867
10020
|
bridgeStarted = true;
|
|
9868
|
-
|
|
10021
|
+
log2("bridge started");
|
|
9869
10022
|
} catch (err) {
|
|
9870
|
-
|
|
10023
|
+
log2("subscribe failed", { err: String(err) });
|
|
9871
10024
|
}
|
|
9872
10025
|
}
|
|
9873
10026
|
|
|
@@ -10440,6 +10593,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10440
10593
|
if (!mounted) return;
|
|
10441
10594
|
setDistinctId(PaywalloClient.getDistinctId());
|
|
10442
10595
|
startSuperwallAutoBridge(configRef.current.debug);
|
|
10596
|
+
void pushAttributionToSuperwall(configRef.current.debug);
|
|
10443
10597
|
setIsInitialized(true);
|
|
10444
10598
|
if (!autoPreloadTriggeredRef.current) {
|
|
10445
10599
|
autoPreloadTriggeredRef.current = true;
|
|
@@ -10475,7 +10629,8 @@ function PaywalloProvider({ children, config }) {
|
|
|
10475
10629
|
placement: preloaded.config.placement,
|
|
10476
10630
|
config: preloaded.config.config,
|
|
10477
10631
|
primaryProductId: preloaded.config.primaryProductId,
|
|
10478
|
-
secondaryProductId: preloaded.config.secondaryProductId
|
|
10632
|
+
secondaryProductId: preloaded.config.secondaryProductId,
|
|
10633
|
+
tertiaryProductId: preloaded.config.tertiaryProductId
|
|
10479
10634
|
},
|
|
10480
10635
|
preloadedProducts: preloaded.products
|
|
10481
10636
|
}
|
|
@@ -10777,6 +10932,9 @@ function resolveProductsVariable(parts, context) {
|
|
|
10777
10932
|
if (parts[1] === "secondary" && context.secondaryProductId) {
|
|
10778
10933
|
return getProductVariable(context.products.get(context.secondaryProductId), parts[2]);
|
|
10779
10934
|
}
|
|
10935
|
+
if (parts[1] === "tertiary" && context.tertiaryProductId) {
|
|
10936
|
+
return getProductVariable(context.products.get(context.tertiaryProductId), parts[2]);
|
|
10937
|
+
}
|
|
10780
10938
|
if (parts[1] === "hasIntroductoryOffer") {
|
|
10781
10939
|
return Array.from(context.products.values()).some((p) => p.introductoryPrice) ? "true" : "false";
|
|
10782
10940
|
}
|