@virex-tech/paywallo-sdk 2.3.0 → 2.4.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/dist/index.js +220 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +220 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -428,11 +428,28 @@ function parseProperties(json) {
|
|
|
428
428
|
return {};
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
|
-
|
|
431
|
+
async function persistAnonIdDurably(storage, anonId) {
|
|
432
|
+
let stored = await storage.set(ANON_ID_KEY, anonId);
|
|
433
|
+
for (let i = 0; i < ANON_ID_SET_RETRIES && !stored; i++) {
|
|
434
|
+
await new Promise((r) => setTimeout(r, ANON_ID_RETRY_DELAY_MS));
|
|
435
|
+
stored = await storage.set(ANON_ID_KEY, anonId);
|
|
436
|
+
}
|
|
437
|
+
if (!stored) {
|
|
438
|
+
await nativeStorage.set(ANON_ID_FALLBACK_KEY, anonId).catch(() => void 0);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
async function readAnonIdDurably(storage) {
|
|
442
|
+
const secure = await readWithMigration(storage, ANON_ID_KEY, LEGACY_ANON_ID_KEY);
|
|
443
|
+
if (secure) return secure;
|
|
444
|
+
return nativeStorage.get(ANON_ID_FALLBACK_KEY);
|
|
445
|
+
}
|
|
446
|
+
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;
|
|
432
447
|
var init_IdentityStorage = __esm({
|
|
433
448
|
"src/domains/identity/IdentityStorage.ts"() {
|
|
434
449
|
"use strict";
|
|
450
|
+
init_NativeStorage();
|
|
435
451
|
DEVICE_ID_KEY = "@paywallo:device_id";
|
|
452
|
+
ANON_ID_FALLBACK_KEY = "@paywallo:anon_id_fallback";
|
|
436
453
|
ANON_ID_KEY = "@paywallo:anon_id";
|
|
437
454
|
USER_EMAIL_KEY = "@paywallo:user_email";
|
|
438
455
|
USER_PROPERTIES_KEY = "@paywallo:user_properties";
|
|
@@ -458,6 +475,8 @@ var init_IdentityStorage = __esm({
|
|
|
458
475
|
LEGACY_NAME_KEY = "user_name";
|
|
459
476
|
LEGACY_COUNTRY_KEY = "user_country";
|
|
460
477
|
LEGACY_LOCALE_KEY = "user_locale";
|
|
478
|
+
ANON_ID_SET_RETRIES = 2;
|
|
479
|
+
ANON_ID_RETRY_DELAY_MS = 50;
|
|
461
480
|
}
|
|
462
481
|
});
|
|
463
482
|
|
|
@@ -537,8 +556,7 @@ var init_IdentityManager = __esm({
|
|
|
537
556
|
}
|
|
538
557
|
if (!this.anonId) {
|
|
539
558
|
this.anonId = generateUUID();
|
|
540
|
-
await this.secureStorage
|
|
541
|
-
});
|
|
559
|
+
await persistAnonIdDurably(this.secureStorage, this.anonId);
|
|
542
560
|
}
|
|
543
561
|
this.initialized = true;
|
|
544
562
|
return this.deviceId ?? "";
|
|
@@ -598,7 +616,8 @@ var init_IdentityManager = __esm({
|
|
|
598
616
|
dateOfBirth: this.dateOfBirth ?? void 0,
|
|
599
617
|
gender: this.gender ?? void 0
|
|
600
618
|
});
|
|
601
|
-
} catch {
|
|
619
|
+
} catch (err) {
|
|
620
|
+
if (this.debug) console.log("[Paywallo] identify dispatch error", err);
|
|
602
621
|
}
|
|
603
622
|
}
|
|
604
623
|
}
|
|
@@ -622,7 +641,8 @@ var init_IdentityManager = __esm({
|
|
|
622
641
|
if (this.apiClient && this.anonId) {
|
|
623
642
|
try {
|
|
624
643
|
await this.apiClient.identify(this.anonId, this.properties, this.email ?? void 0, this.deviceId ?? void 0);
|
|
625
|
-
} catch {
|
|
644
|
+
} catch (err) {
|
|
645
|
+
if (this.debug) console.log("[Paywallo] identify dispatch error", err);
|
|
626
646
|
}
|
|
627
647
|
}
|
|
628
648
|
}
|
|
@@ -665,18 +685,20 @@ var init_IdentityManager = __esm({
|
|
|
665
685
|
}
|
|
666
686
|
async loadPersistedState() {
|
|
667
687
|
if (!this.secureStorage) return;
|
|
668
|
-
const state = await
|
|
688
|
+
const [state, rawAnonId] = await Promise.all([
|
|
689
|
+
loadPersistedIdentity(this.secureStorage),
|
|
690
|
+
readAnonIdDurably(this.secureStorage)
|
|
691
|
+
]);
|
|
669
692
|
const deviceId = state.deviceId ?? await readDeviceIdWithFallback(this.secureStorage);
|
|
670
693
|
if (deviceId) this.deviceId = deviceId;
|
|
671
|
-
if (
|
|
694
|
+
if (rawAnonId) {
|
|
672
695
|
const legacyPrefix = "$paywallo_anon:";
|
|
673
|
-
if (
|
|
674
|
-
const stripped =
|
|
696
|
+
if (rawAnonId.startsWith(legacyPrefix)) {
|
|
697
|
+
const stripped = rawAnonId.slice(legacyPrefix.length);
|
|
675
698
|
this.anonId = stripped;
|
|
676
|
-
await this.secureStorage.set(ANON_ID_KEY, stripped).catch(() =>
|
|
677
|
-
});
|
|
699
|
+
await this.secureStorage.set(ANON_ID_KEY, stripped).catch(() => void 0);
|
|
678
700
|
} else {
|
|
679
|
-
this.anonId =
|
|
701
|
+
this.anonId = rawAnonId;
|
|
680
702
|
}
|
|
681
703
|
}
|
|
682
704
|
if (state.email) this.email = state.email;
|
|
@@ -901,21 +923,23 @@ var init_AdvertisingIdManager = __esm({
|
|
|
901
923
|
if (import_react_native3.Platform.OS === "ios") {
|
|
902
924
|
if (!tracking.isAvailable()) {
|
|
903
925
|
const idfv2 = await this.collectIdfv();
|
|
904
|
-
|
|
905
|
-
|
|
926
|
+
const result2 = { ...fallback, idfv: idfv2 };
|
|
927
|
+
if (idfv2 !== null) this.cached = result2;
|
|
928
|
+
return result2;
|
|
906
929
|
}
|
|
907
930
|
const current = await tracking.getTrackingPermissionsAsync();
|
|
908
931
|
let status = current.status;
|
|
909
932
|
let granted = current.granted;
|
|
910
933
|
if (status === "undetermined" && requestATT) {
|
|
911
|
-
const
|
|
912
|
-
status =
|
|
913
|
-
granted =
|
|
934
|
+
const result2 = await tracking.requestTrackingPermissionsAsync();
|
|
935
|
+
status = result2.status;
|
|
936
|
+
granted = result2.granted;
|
|
914
937
|
}
|
|
915
938
|
const idfv = await this.collectIdfv();
|
|
916
939
|
const idfa = granted ? this.sanitizeId(tracking.getAdvertisingId()) : null;
|
|
917
|
-
|
|
918
|
-
|
|
940
|
+
const result = { idfv, idfa, gaid: null, attStatus: status };
|
|
941
|
+
if (idfv !== null) this.cached = result;
|
|
942
|
+
return result;
|
|
919
943
|
}
|
|
920
944
|
if (import_react_native3.Platform.OS === "android") {
|
|
921
945
|
const rawGaid = tracking.getAdvertisingId();
|
|
@@ -931,12 +955,20 @@ var init_AdvertisingIdManager = __esm({
|
|
|
931
955
|
}
|
|
932
956
|
}
|
|
933
957
|
async collectIdfv() {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
958
|
+
const RETRY_DELAY_MS = 80;
|
|
959
|
+
const MAX_ATTEMPTS = 3;
|
|
960
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
961
|
+
try {
|
|
962
|
+
const info = await nativeDeviceInfo.getDeviceInfo();
|
|
963
|
+
const idfv = this.sanitizeId(info.idfv);
|
|
964
|
+
if (idfv !== null) return idfv;
|
|
965
|
+
} catch {
|
|
966
|
+
}
|
|
967
|
+
if (attempt < MAX_ATTEMPTS - 1) {
|
|
968
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
969
|
+
}
|
|
939
970
|
}
|
|
971
|
+
return null;
|
|
940
972
|
}
|
|
941
973
|
sanitizeId(id) {
|
|
942
974
|
if (!id || id === ZERO_IDFA) return null;
|
|
@@ -1374,6 +1406,8 @@ var init_AttributionTracker = __esm({
|
|
|
1374
1406
|
|
|
1375
1407
|
// src/domains/identity/InstallIdempotency.ts
|
|
1376
1408
|
async function checkAndArmInstallGuard(storage) {
|
|
1409
|
+
if (armedThisLaunch) return true;
|
|
1410
|
+
armedThisLaunch = true;
|
|
1377
1411
|
const alreadyTracked = await storage.get(INSTALL_KEYS.INSTALL_TRACKED);
|
|
1378
1412
|
if (alreadyTracked) return true;
|
|
1379
1413
|
let fallbackTracked = null;
|
|
@@ -1407,7 +1441,7 @@ async function getOrCreateInstallEventId() {
|
|
|
1407
1441
|
});
|
|
1408
1442
|
return id;
|
|
1409
1443
|
}
|
|
1410
|
-
var INSTALL_KEYS;
|
|
1444
|
+
var INSTALL_KEYS, armedThisLaunch;
|
|
1411
1445
|
var init_InstallIdempotency = __esm({
|
|
1412
1446
|
"src/domains/identity/InstallIdempotency.ts"() {
|
|
1413
1447
|
"use strict";
|
|
@@ -1432,6 +1466,7 @@ var init_InstallIdempotency = __esm({
|
|
|
1432
1466
|
/** Legacy anon ID key written by SDK versions that used @panel: prefix. */
|
|
1433
1467
|
LEGACY_ANON_ID: "@panel:anon_id"
|
|
1434
1468
|
};
|
|
1469
|
+
armedThisLaunch = false;
|
|
1435
1470
|
}
|
|
1436
1471
|
});
|
|
1437
1472
|
|
|
@@ -2386,8 +2421,8 @@ var init_NotificationHandlerSetup = __esm({
|
|
|
2386
2421
|
// src/core/version.ts
|
|
2387
2422
|
function resolveVersion() {
|
|
2388
2423
|
try {
|
|
2389
|
-
if ("2.
|
|
2390
|
-
return "2.
|
|
2424
|
+
if ("2.4.1") {
|
|
2425
|
+
return "2.4.1";
|
|
2391
2426
|
}
|
|
2392
2427
|
} catch {
|
|
2393
2428
|
}
|
|
@@ -4249,10 +4284,10 @@ var init_OfflineQueueStorage = __esm({
|
|
|
4249
4284
|
init_NativeStorage();
|
|
4250
4285
|
init_QueueJournal();
|
|
4251
4286
|
OfflineQueueStorage = class {
|
|
4252
|
-
constructor(config, emit,
|
|
4287
|
+
constructor(config, emit, log3) {
|
|
4253
4288
|
this.config = config;
|
|
4254
4289
|
this.emit = emit;
|
|
4255
|
-
this.log =
|
|
4290
|
+
this.log = log3;
|
|
4256
4291
|
}
|
|
4257
4292
|
async loadFromStorage(queue) {
|
|
4258
4293
|
const { merged, recovered, hadJournal } = await mergeJournalIntoMain(
|
|
@@ -4501,11 +4536,11 @@ var init_OfflineQueue = __esm({
|
|
|
4501
4536
|
});
|
|
4502
4537
|
return true;
|
|
4503
4538
|
}
|
|
4504
|
-
const
|
|
4539
|
+
const delay2 = Math.min(
|
|
4505
4540
|
this.config.baseRetryDelayMs * Math.pow(2, item.attempts - 1),
|
|
4506
4541
|
this.config.maxRetryDelayMs
|
|
4507
4542
|
);
|
|
4508
|
-
item.nextRetryAt = Date.now() +
|
|
4543
|
+
item.nextRetryAt = Date.now() + delay2;
|
|
4509
4544
|
await this.storage.saveToStorage(this.queue);
|
|
4510
4545
|
return false;
|
|
4511
4546
|
}
|
|
@@ -7778,8 +7813,8 @@ var init_HttpClient = __esm({
|
|
|
7778
7813
|
if (this.shouldRetry(response.status, retryConfig)) {
|
|
7779
7814
|
if (state.attempt < retryConfig.maxRetries) {
|
|
7780
7815
|
state.attempt++;
|
|
7781
|
-
const
|
|
7782
|
-
await this.sleep(
|
|
7816
|
+
const delay2 = this.calculateDelayForResponse(state.attempt, response.headers, retryConfig);
|
|
7817
|
+
await this.sleep(delay2);
|
|
7783
7818
|
continue;
|
|
7784
7819
|
}
|
|
7785
7820
|
}
|
|
@@ -7788,8 +7823,8 @@ var init_HttpClient = __esm({
|
|
|
7788
7823
|
state.lastError = error instanceof Error ? error : new ClientError(CLIENT_ERROR_CODES.UNKNOWN, String(error));
|
|
7789
7824
|
if (this.isNetworkError(state.lastError) && state.attempt < retryConfig.maxRetries) {
|
|
7790
7825
|
state.attempt++;
|
|
7791
|
-
const
|
|
7792
|
-
await this.sleep(
|
|
7826
|
+
const delay2 = this.calculateDelay(state.attempt, retryConfig);
|
|
7827
|
+
await this.sleep(delay2);
|
|
7793
7828
|
continue;
|
|
7794
7829
|
}
|
|
7795
7830
|
throw state.lastError;
|
|
@@ -7937,7 +7972,36 @@ var init_http = __esm({
|
|
|
7937
7972
|
});
|
|
7938
7973
|
|
|
7939
7974
|
// src/core/ApiClient.ts
|
|
7940
|
-
|
|
7975
|
+
function normalizeDateOfBirth(raw) {
|
|
7976
|
+
if (!raw) return void 0;
|
|
7977
|
+
if (DATE_OF_BIRTH_RE.test(raw)) return raw;
|
|
7978
|
+
const d = new Date(raw);
|
|
7979
|
+
if (isNaN(d.getTime())) return void 0;
|
|
7980
|
+
const hasTimeComponent = raw.includes("T") || raw.includes("Z");
|
|
7981
|
+
const yyyy = hasTimeComponent ? d.getUTCFullYear() : d.getFullYear();
|
|
7982
|
+
const mm = String((hasTimeComponent ? d.getUTCMonth() : d.getMonth()) + 1).padStart(2, "0");
|
|
7983
|
+
const dd = String(hasTimeComponent ? d.getUTCDate() : d.getDate()).padStart(2, "0");
|
|
7984
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
7985
|
+
}
|
|
7986
|
+
function buildPiiPayload(pii) {
|
|
7987
|
+
const result = {};
|
|
7988
|
+
if (pii.phone) result.phone = pii.phone;
|
|
7989
|
+
if (pii.firstName) result.firstName = pii.firstName;
|
|
7990
|
+
if (pii.lastName) result.lastName = pii.lastName;
|
|
7991
|
+
const dob = normalizeDateOfBirth(pii.dateOfBirth);
|
|
7992
|
+
if (dob) result.dateOfBirth = dob;
|
|
7993
|
+
const g = normalizeGender(pii.gender);
|
|
7994
|
+
if (g) result.gender = g;
|
|
7995
|
+
return result;
|
|
7996
|
+
}
|
|
7997
|
+
function normalizeGender(raw) {
|
|
7998
|
+
if (!raw) return void 0;
|
|
7999
|
+
const lower = raw.toLowerCase();
|
|
8000
|
+
if (lower === "m" || lower === "male") return "m";
|
|
8001
|
+
if (lower === "f" || lower === "female") return "f";
|
|
8002
|
+
return void 0;
|
|
8003
|
+
}
|
|
8004
|
+
var import_react_native25, DATE_OF_BIRTH_RE, ApiClient;
|
|
7941
8005
|
var init_ApiClient = __esm({
|
|
7942
8006
|
"src/core/ApiClient.ts"() {
|
|
7943
8007
|
"use strict";
|
|
@@ -7951,6 +8015,7 @@ var init_ApiClient = __esm({
|
|
|
7951
8015
|
init_http();
|
|
7952
8016
|
init_queue();
|
|
7953
8017
|
init_version();
|
|
8018
|
+
DATE_OF_BIRTH_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
7954
8019
|
ApiClient = class {
|
|
7955
8020
|
constructor(appKey, apiUrl, debug = false, environment = "Production", offlineQueueEnabled = true, timeout = 3e4) {
|
|
7956
8021
|
this.cache = new ApiCache();
|
|
@@ -8125,11 +8190,7 @@ var init_ApiClient = __esm({
|
|
|
8125
8190
|
traits,
|
|
8126
8191
|
...attribution && { attribution },
|
|
8127
8192
|
...deviceId && { deviceId },
|
|
8128
|
-
...pii
|
|
8129
|
-
...pii?.firstName && { firstName: pii.firstName },
|
|
8130
|
-
...pii?.lastName && { lastName: pii.lastName },
|
|
8131
|
-
...pii?.dateOfBirth && { dateOfBirth: pii.dateOfBirth },
|
|
8132
|
-
...pii?.gender && { gender: pii.gender }
|
|
8193
|
+
...pii ? buildPiiPayload(pii) : {}
|
|
8133
8194
|
},
|
|
8134
8195
|
"identify"
|
|
8135
8196
|
);
|
|
@@ -8414,8 +8475,8 @@ async function initWithRetry(state, config) {
|
|
|
8414
8475
|
} catch (error) {
|
|
8415
8476
|
state.initAttempts++;
|
|
8416
8477
|
if (state.initAttempts > MAX_INIT_RETRIES) throw error;
|
|
8417
|
-
const
|
|
8418
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
8478
|
+
const delay2 = RETRY_DELAYS[state.initAttempts - 1] ?? 1e4;
|
|
8479
|
+
await new Promise((resolve) => setTimeout(resolve, delay2));
|
|
8419
8480
|
}
|
|
8420
8481
|
}
|
|
8421
8482
|
}
|
|
@@ -9769,6 +9830,108 @@ init_paywall();
|
|
|
9769
9830
|
init_paywall();
|
|
9770
9831
|
init_paywall();
|
|
9771
9832
|
|
|
9833
|
+
// src/domains/paywall/SuperwallAttributeBridge.ts
|
|
9834
|
+
init_identity();
|
|
9835
|
+
var CONFIG_POLL_INTERVAL_MS = 250;
|
|
9836
|
+
var CONFIG_POLL_MAX_ATTEMPTS = 40;
|
|
9837
|
+
var lastSignature = null;
|
|
9838
|
+
function log(debug, msg, data) {
|
|
9839
|
+
if (!debug) return;
|
|
9840
|
+
if (data !== void 0) console.log(`[Paywallo:SuperwallAttr] ${msg}`, data);
|
|
9841
|
+
else console.log(`[Paywallo:SuperwallAttr] ${msg}`);
|
|
9842
|
+
}
|
|
9843
|
+
function delay(ms) {
|
|
9844
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
9845
|
+
}
|
|
9846
|
+
var PAID_MEDIUM = /cpc|ppc|cpm|cpa|paid|display/i;
|
|
9847
|
+
function deriveIsPaid(a) {
|
|
9848
|
+
if (a.fbclid || a.gclid || a.ttclid || a.tiktokCampaignId) return true;
|
|
9849
|
+
return Boolean(a.utmMedium && PAID_MEDIUM.test(a.utmMedium));
|
|
9850
|
+
}
|
|
9851
|
+
function deriveAdNetwork(a) {
|
|
9852
|
+
if (a.fbclid) return "meta";
|
|
9853
|
+
if (a.ttclid || a.tiktokCampaignId) return "tiktok";
|
|
9854
|
+
if (a.gclid) return "google";
|
|
9855
|
+
return a.utmSource;
|
|
9856
|
+
}
|
|
9857
|
+
function buildSuperwallAttributes(a) {
|
|
9858
|
+
const out = {};
|
|
9859
|
+
if (!a) {
|
|
9860
|
+
out.pw_is_paid = false;
|
|
9861
|
+
return out;
|
|
9862
|
+
}
|
|
9863
|
+
const set2 = (key, value) => {
|
|
9864
|
+
if (value) out[key] = value;
|
|
9865
|
+
};
|
|
9866
|
+
set2("pw_utm_source", a.utmSource);
|
|
9867
|
+
set2("pw_utm_medium", a.utmMedium);
|
|
9868
|
+
set2("pw_utm_campaign", a.utmCampaign);
|
|
9869
|
+
set2("pw_utm_content", a.utmContent);
|
|
9870
|
+
set2("pw_utm_term", a.utmTerm);
|
|
9871
|
+
set2("pw_fbclid", a.fbclid);
|
|
9872
|
+
set2("pw_gclid", a.gclid);
|
|
9873
|
+
set2("pw_ttclid", a.ttclid);
|
|
9874
|
+
set2("pw_tiktok_campaign_id", a.tiktokCampaignId);
|
|
9875
|
+
set2("pw_tiktok_adgroup_id", a.tiktokAdgroupId);
|
|
9876
|
+
set2("pw_tiktok_ad_id", a.tiktokAdId);
|
|
9877
|
+
set2("pw_referrer", a.referrer);
|
|
9878
|
+
set2("pw_install_referrer_source", a.installReferrerSource);
|
|
9879
|
+
set2("pw_ad_network", deriveAdNetwork(a));
|
|
9880
|
+
out.pw_is_paid = deriveIsPaid(a);
|
|
9881
|
+
out.pw_attributed_at = a.capturedAt;
|
|
9882
|
+
return out;
|
|
9883
|
+
}
|
|
9884
|
+
function pickNative(mod) {
|
|
9885
|
+
const native = mod?.SuperwallExpoModule ?? mod?.default?.SuperwallExpoModule;
|
|
9886
|
+
return native && typeof native.setUserAttributes === "function" && typeof native.getConfigurationStatus === "function" ? native : null;
|
|
9887
|
+
}
|
|
9888
|
+
async function resolveSuperwallNativeModule(debug) {
|
|
9889
|
+
try {
|
|
9890
|
+
const native = pickNative(await import("expo-superwall"));
|
|
9891
|
+
if (native) return native;
|
|
9892
|
+
} catch {
|
|
9893
|
+
}
|
|
9894
|
+
log(debug, "expo-superwall native module not available \u2014 attribute push skipped");
|
|
9895
|
+
return null;
|
|
9896
|
+
}
|
|
9897
|
+
async function waitForConfigured(mod, debug) {
|
|
9898
|
+
for (let attempt = 0; attempt < CONFIG_POLL_MAX_ATTEMPTS; attempt++) {
|
|
9899
|
+
let status;
|
|
9900
|
+
try {
|
|
9901
|
+
status = String(await mod.getConfigurationStatus());
|
|
9902
|
+
} catch (err) {
|
|
9903
|
+
log(debug, "getConfigurationStatus error", { err: String(err) });
|
|
9904
|
+
return false;
|
|
9905
|
+
}
|
|
9906
|
+
if (status === "CONFIGURED") return true;
|
|
9907
|
+
if (status === "FAILED") {
|
|
9908
|
+
log(debug, "Superwall configuration FAILED \u2014 skipping attribute push");
|
|
9909
|
+
return false;
|
|
9910
|
+
}
|
|
9911
|
+
await delay(CONFIG_POLL_INTERVAL_MS);
|
|
9912
|
+
}
|
|
9913
|
+
log(debug, "Superwall not configured within timeout \u2014 skipping attribute push");
|
|
9914
|
+
return false;
|
|
9915
|
+
}
|
|
9916
|
+
async function pushAttributionToSuperwall(debug = false) {
|
|
9917
|
+
const attrs = buildSuperwallAttributes(attributionTracker.get());
|
|
9918
|
+
const signature = JSON.stringify(attrs);
|
|
9919
|
+
if (signature === lastSignature) {
|
|
9920
|
+
log(debug, "attributes unchanged \u2014 skipping push");
|
|
9921
|
+
return;
|
|
9922
|
+
}
|
|
9923
|
+
const native = await resolveSuperwallNativeModule(debug);
|
|
9924
|
+
if (!native) return;
|
|
9925
|
+
if (!await waitForConfigured(native, debug)) return;
|
|
9926
|
+
try {
|
|
9927
|
+
await native.setUserAttributes(attrs);
|
|
9928
|
+
lastSignature = signature;
|
|
9929
|
+
log(debug, "attributes pushed to Superwall", attrs);
|
|
9930
|
+
} catch (err) {
|
|
9931
|
+
log(debug, "setUserAttributes error", { err: String(err) });
|
|
9932
|
+
}
|
|
9933
|
+
}
|
|
9934
|
+
|
|
9772
9935
|
// src/domains/paywall/SuperwallAutoBridge.ts
|
|
9773
9936
|
init_PaywalloClient();
|
|
9774
9937
|
|
|
@@ -9802,7 +9965,7 @@ function buildDeterministicEventId(parts) {
|
|
|
9802
9965
|
var bridgeStarted = false;
|
|
9803
9966
|
var unsubscribe = null;
|
|
9804
9967
|
var debugEnabled = false;
|
|
9805
|
-
function
|
|
9968
|
+
function log2(msg, data) {
|
|
9806
9969
|
if (!debugEnabled) return;
|
|
9807
9970
|
if (data !== void 0) {
|
|
9808
9971
|
console.log(`[Paywallo:SuperwallBridge] ${msg}`, data);
|
|
@@ -9832,7 +9995,7 @@ async function trackPaywallEvent(type, identifier, ts, extra) {
|
|
|
9832
9995
|
}
|
|
9833
9996
|
});
|
|
9834
9997
|
} catch (err) {
|
|
9835
|
-
|
|
9998
|
+
log2("track error", { type, identifier, eventId: _eventId, err: String(err) });
|
|
9836
9999
|
}
|
|
9837
10000
|
}
|
|
9838
10001
|
function mapDismissToCloseReason(resultType) {
|
|
@@ -9852,7 +10015,7 @@ function buildCallbacks() {
|
|
|
9852
10015
|
return {
|
|
9853
10016
|
onPaywallPresent: (info) => {
|
|
9854
10017
|
const ts = Date.now();
|
|
9855
|
-
|
|
10018
|
+
log2("onPaywallPresent", { identifier: info.identifier });
|
|
9856
10019
|
void trackPaywallEvent("viewed", info.identifier, ts, {
|
|
9857
10020
|
placement: info.presentedByEventWithName,
|
|
9858
10021
|
variant_id: info.experiment?.variant?.id,
|
|
@@ -9861,7 +10024,7 @@ function buildCallbacks() {
|
|
|
9861
10024
|
},
|
|
9862
10025
|
onPaywallDismiss: (info, result) => {
|
|
9863
10026
|
const ts = Date.now();
|
|
9864
|
-
|
|
10027
|
+
log2("onPaywallDismiss", { identifier: info.identifier, result: result.type });
|
|
9865
10028
|
void trackPaywallEvent("closed", info.identifier, ts, {
|
|
9866
10029
|
placement: info.presentedByEventWithName,
|
|
9867
10030
|
variant_id: info.experiment?.variant?.id,
|
|
@@ -9875,7 +10038,7 @@ function buildCallbacks() {
|
|
|
9875
10038
|
const safe = params !== null && typeof params === "object" ? params : {};
|
|
9876
10039
|
const productId = "productId" in safe && typeof safe.productId === "string" ? safe.productId : "unknown";
|
|
9877
10040
|
const identifier = "paywallIdentifier" in safe && typeof safe.paywallIdentifier === "string" ? safe.paywallIdentifier : productId;
|
|
9878
|
-
|
|
10041
|
+
log2("onPurchase", { productId, identifier });
|
|
9879
10042
|
void trackPaywallEvent("purchased", identifier, ts, { product_id: productId });
|
|
9880
10043
|
},
|
|
9881
10044
|
// Global Superwall event listener — used specifically for `transactionComplete`
|
|
@@ -9890,7 +10053,7 @@ function buildCallbacks() {
|
|
|
9890
10053
|
const product = ev.product;
|
|
9891
10054
|
const transaction = ev.transaction;
|
|
9892
10055
|
if (!product) {
|
|
9893
|
-
|
|
10056
|
+
log2("transactionComplete missing product \u2014 skipping transaction track");
|
|
9894
10057
|
return;
|
|
9895
10058
|
}
|
|
9896
10059
|
const productId = product.productIdentifier ?? product.id ?? "unknown";
|
|
@@ -9899,7 +10062,7 @@ function buildCallbacks() {
|
|
|
9899
10062
|
const transactionId = transaction?.storeTransactionId ?? transaction?.originalTransactionIdentifier ?? `${productId}_${String(ts)}`;
|
|
9900
10063
|
const isTrial = product.hasFreeTrial === true || (product.trialPeriodPrice ?? 0) > 0;
|
|
9901
10064
|
const paywallIdentifier = ev.paywallInfo?.identifier;
|
|
9902
|
-
|
|
10065
|
+
log2("onSuperwallEvent: transactionComplete", { productId, currency, price, transactionId, isTrial });
|
|
9903
10066
|
void (async () => {
|
|
9904
10067
|
try {
|
|
9905
10068
|
await PaywalloClient.track("transaction", {
|
|
@@ -9917,7 +10080,7 @@ function buildCallbacks() {
|
|
|
9917
10080
|
}
|
|
9918
10081
|
});
|
|
9919
10082
|
} catch (err) {
|
|
9920
|
-
|
|
10083
|
+
log2("transactionComplete track error", { err: String(err) });
|
|
9921
10084
|
}
|
|
9922
10085
|
})();
|
|
9923
10086
|
}
|
|
@@ -9926,7 +10089,7 @@ function buildCallbacks() {
|
|
|
9926
10089
|
function startSuperwallAutoBridge(debug = false) {
|
|
9927
10090
|
debugEnabled = debug;
|
|
9928
10091
|
if (bridgeStarted) {
|
|
9929
|
-
|
|
10092
|
+
log2("already started, skipping");
|
|
9930
10093
|
return;
|
|
9931
10094
|
}
|
|
9932
10095
|
void detectAndStart();
|
|
@@ -9938,7 +10101,7 @@ async function detectAndStart() {
|
|
|
9938
10101
|
if (!mod || typeof mod.subscribeToSuperwallEvents !== "function") {
|
|
9939
10102
|
const internal = await import("expo-superwall/build/src/internal/superwallEventBridge");
|
|
9940
10103
|
if (typeof internal.subscribeToSuperwallEvents !== "function") {
|
|
9941
|
-
|
|
10104
|
+
log2("expo-superwall subscribeToSuperwallEvents not found \u2014 bridge inactive");
|
|
9942
10105
|
return;
|
|
9943
10106
|
}
|
|
9944
10107
|
subscribeFn = internal.subscribeToSuperwallEvents;
|
|
@@ -9946,16 +10109,16 @@ async function detectAndStart() {
|
|
|
9946
10109
|
subscribeFn = mod.subscribeToSuperwallEvents;
|
|
9947
10110
|
}
|
|
9948
10111
|
} catch {
|
|
9949
|
-
|
|
10112
|
+
log2("expo-superwall not installed \u2014 bridge inactive");
|
|
9950
10113
|
return;
|
|
9951
10114
|
}
|
|
9952
10115
|
try {
|
|
9953
10116
|
const callbacks = buildCallbacks();
|
|
9954
10117
|
unsubscribe = subscribeFn(void 0, () => callbacks);
|
|
9955
10118
|
bridgeStarted = true;
|
|
9956
|
-
|
|
10119
|
+
log2("bridge started");
|
|
9957
10120
|
} catch (err) {
|
|
9958
|
-
|
|
10121
|
+
log2("subscribe failed", { err: String(err) });
|
|
9959
10122
|
}
|
|
9960
10123
|
}
|
|
9961
10124
|
|
|
@@ -10528,6 +10691,7 @@ function PaywalloProvider({ children, config }) {
|
|
|
10528
10691
|
if (!mounted) return;
|
|
10529
10692
|
setDistinctId(PaywalloClient.getDistinctId());
|
|
10530
10693
|
startSuperwallAutoBridge(configRef.current.debug);
|
|
10694
|
+
void pushAttributionToSuperwall(configRef.current.debug);
|
|
10531
10695
|
setIsInitialized(true);
|
|
10532
10696
|
if (!autoPreloadTriggeredRef.current) {
|
|
10533
10697
|
autoPreloadTriggeredRef.current = true;
|