@virex-tech/paywallo-sdk 2.6.0 → 2.6.2

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.mjs CHANGED
@@ -475,7 +475,7 @@ async function readAnonIdDurably(storage) {
475
475
  if (secure) return secure;
476
476
  return nativeStorage.get(ANON_ID_FALLBACK_KEY);
477
477
  }
478
- 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;
478
+ 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, USER_ZIP_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;
479
479
  var init_IdentityStorage = __esm({
480
480
  "src/domains/identity/IdentityStorage.ts"() {
481
481
  "use strict";
@@ -494,6 +494,7 @@ var init_IdentityStorage = __esm({
494
494
  USER_LAST_NAME_KEY = "@paywallo:user_last_name";
495
495
  USER_DOB_KEY = "@paywallo:user_dob";
496
496
  USER_GENDER_KEY = "@paywallo:user_gender";
497
+ USER_ZIP_KEY = "@paywallo:user_zip";
497
498
  LEGACY_USER_PHONE_KEY = "@panel:user_phone";
498
499
  LEGACY_USER_FIRST_NAME_KEY = "@panel:user_first_name";
499
500
  LEGACY_USER_LAST_NAME_KEY = "@panel:user_last_name";
@@ -544,6 +545,7 @@ var init_IdentityManager = __esm({
544
545
  this.lastName = null;
545
546
  this.dateOfBirth = null;
546
547
  this.gender = null;
548
+ this.zipCode = null;
547
549
  this.apiClient = null;
548
550
  this.secureStorage = null;
549
551
  this.debug = false;
@@ -598,7 +600,7 @@ var init_IdentityManager = __esm({
598
600
  let email;
599
601
  let properties;
600
602
  if (options) {
601
- if ("email" in options || "properties" in options || "phone" in options || "firstName" in options || "lastName" in options || "dateOfBirth" in options || "gender" in options) {
603
+ if ("email" in options || "properties" in options || "phone" in options || "firstName" in options || "lastName" in options || "dateOfBirth" in options || "gender" in options || "zipCode" in options) {
602
604
  email = options.email;
603
605
  properties = options.properties;
604
606
  } else {
@@ -639,6 +641,10 @@ var init_IdentityManager = __esm({
639
641
  this.gender = opts.gender;
640
642
  await this.secureStorage.set(USER_GENDER_KEY, this.gender);
641
643
  }
644
+ if (opts?.zipCode) {
645
+ this.zipCode = opts.zipCode;
646
+ await this.secureStorage.set(USER_ZIP_KEY, this.zipCode);
647
+ }
642
648
  if (this.apiClient && this.anonId) {
643
649
  try {
644
650
  await this.apiClient.identify(this.anonId, properties, email, this.deviceId ?? void 0, {
@@ -646,7 +652,8 @@ var init_IdentityManager = __esm({
646
652
  firstName: this.firstName ?? void 0,
647
653
  lastName: this.lastName ?? void 0,
648
654
  dateOfBirth: this.dateOfBirth ?? void 0,
649
- gender: this.gender ?? void 0
655
+ gender: this.gender ?? void 0,
656
+ zipCode: this.zipCode ?? void 0
650
657
  });
651
658
  if (this.debug) console.log("[Paywallo] identify confirmed", this.anonId.slice(0, 8));
652
659
  } catch (err) {
@@ -696,6 +703,7 @@ var init_IdentityManager = __esm({
696
703
  this.lastName = null;
697
704
  this.dateOfBirth = null;
698
705
  this.gender = null;
706
+ this.zipCode = null;
699
707
  await Promise.all([
700
708
  this.secureStorage?.set(ANON_ID_KEY, newAnonId) ?? Promise.resolve(false),
701
709
  this.secureStorage?.remove(USER_EMAIL_KEY) ?? Promise.resolve(false),
@@ -704,7 +712,8 @@ var init_IdentityManager = __esm({
704
712
  this.secureStorage?.remove(USER_FIRST_NAME_KEY) ?? Promise.resolve(false),
705
713
  this.secureStorage?.remove(USER_LAST_NAME_KEY) ?? Promise.resolve(false),
706
714
  this.secureStorage?.remove(USER_DOB_KEY) ?? Promise.resolve(false),
707
- this.secureStorage?.remove(USER_GENDER_KEY) ?? Promise.resolve(false)
715
+ this.secureStorage?.remove(USER_GENDER_KEY) ?? Promise.resolve(false),
716
+ this.secureStorage?.remove(USER_ZIP_KEY) ?? Promise.resolve(false)
708
717
  ]);
709
718
  }
710
719
  getState() {
@@ -716,7 +725,8 @@ var init_IdentityManager = __esm({
716
725
  firstName: this.firstName,
717
726
  lastName: this.lastName,
718
727
  dateOfBirth: this.dateOfBirth,
719
- gender: this.gender
728
+ gender: this.gender,
729
+ zipCode: this.zipCode
720
730
  };
721
731
  }
722
732
  isSecureStorageAvailable() {
@@ -934,17 +944,39 @@ var init_campaign = __esm({
934
944
  }
935
945
  });
936
946
 
947
+ // src/domains/identity/NativeAdvertisingId.ts
948
+ import { NativeModules as NativeModules2 } from "react-native";
949
+ var nativeModule, nativeAdvertisingId;
950
+ var init_NativeAdvertisingId = __esm({
951
+ "src/domains/identity/NativeAdvertisingId.ts"() {
952
+ "use strict";
953
+ nativeModule = NativeModules2.PaywalloAdvertisingId ?? null;
954
+ nativeAdvertisingId = {
955
+ async getAdvertisingId() {
956
+ try {
957
+ return await nativeModule?.getAdvertisingId?.() ?? null;
958
+ } catch {
959
+ return null;
960
+ }
961
+ }
962
+ };
963
+ }
964
+ });
965
+
937
966
  // src/domains/identity/AdvertisingIdManager.ts
938
967
  import { Platform as Platform2 } from "react-native";
939
- var ZERO_IDFA, AdvertisingIdManager, advertisingIdManager;
968
+ var ZERO_IDFA, ATT_PROMPT_TIMEOUT_MS, AdvertisingIdManager, advertisingIdManager;
940
969
  var init_AdvertisingIdManager = __esm({
941
970
  "src/domains/identity/AdvertisingIdManager.ts"() {
942
971
  "use strict";
943
972
  init_NativeDeviceInfo();
973
+ init_NativeAdvertisingId();
944
974
  ZERO_IDFA = "00000000-0000-0000-0000-000000000000";
975
+ ATT_PROMPT_TIMEOUT_MS = 4e3;
945
976
  AdvertisingIdManager = class {
946
- constructor() {
977
+ constructor(debug = false) {
947
978
  this.cached = null;
979
+ this.debug = debug;
948
980
  }
949
981
  /**
950
982
  * Synchronous accessor for the cached collect() result. Returns null until
@@ -959,6 +991,9 @@ var init_AdvertisingIdManager = __esm({
959
991
  return this.cached;
960
992
  }
961
993
  const fallback = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
994
+ if (Platform2.OS === "android") {
995
+ return this.collectAndroid();
996
+ }
962
997
  try {
963
998
  const tracking = await import("expo-tracking-transparency");
964
999
  if (Platform2.OS === "ios") {
@@ -972,9 +1007,20 @@ var init_AdvertisingIdManager = __esm({
972
1007
  let status = current.status;
973
1008
  let granted = current.granted;
974
1009
  if (status === "undetermined" && requestATT) {
975
- const result2 = await tracking.requestTrackingPermissionsAsync();
976
- status = result2.status;
977
- granted = result2.granted;
1010
+ const result2 = await Promise.race([
1011
+ tracking.requestTrackingPermissionsAsync(),
1012
+ new Promise((r) => setTimeout(() => r(null), ATT_PROMPT_TIMEOUT_MS))
1013
+ ]);
1014
+ if (result2 === null) {
1015
+ if (this.debug) {
1016
+ console.log(`[Paywallo] ATT prompt timed out after ${ATT_PROMPT_TIMEOUT_MS}ms \u2014 treating as undetermined`);
1017
+ }
1018
+ status = "undetermined";
1019
+ granted = false;
1020
+ } else {
1021
+ status = result2.status;
1022
+ granted = result2.granted;
1023
+ }
978
1024
  }
979
1025
  const idfv = await this.collectIdfv();
980
1026
  const idfa = granted ? this.sanitizeId(tracking.getAdvertisingId()) : null;
@@ -982,12 +1028,6 @@ var init_AdvertisingIdManager = __esm({
982
1028
  if (idfv !== null) this.cached = result;
983
1029
  return result;
984
1030
  }
985
- if (Platform2.OS === "android") {
986
- const rawGaid = tracking.getAdvertisingId();
987
- const gaid = this.sanitizeId(rawGaid);
988
- this.cached = { idfv: null, idfa: null, gaid, attStatus: "unavailable" };
989
- return this.cached;
990
- }
991
1031
  this.cached = fallback;
992
1032
  return this.cached;
993
1033
  } catch {
@@ -995,6 +1035,27 @@ var init_AdvertisingIdManager = __esm({
995
1035
  return this.cached;
996
1036
  }
997
1037
  }
1038
+ async collectAndroid() {
1039
+ const nativeGaid = this.sanitizeId(
1040
+ await Promise.race([
1041
+ nativeAdvertisingId.getAdvertisingId(),
1042
+ new Promise((r) => setTimeout(() => r(null), 1500))
1043
+ ])
1044
+ );
1045
+ if (nativeGaid !== null) {
1046
+ this.cached = { idfv: null, idfa: null, gaid: nativeGaid, attStatus: "unavailable" };
1047
+ return this.cached;
1048
+ }
1049
+ try {
1050
+ const tracking = await import("expo-tracking-transparency");
1051
+ const gaid = this.sanitizeId(tracking.getAdvertisingId());
1052
+ this.cached = { idfv: null, idfa: null, gaid, attStatus: "unavailable" };
1053
+ return this.cached;
1054
+ } catch {
1055
+ this.cached = { idfv: null, idfa: null, gaid: null, attStatus: "unavailable" };
1056
+ return this.cached;
1057
+ }
1058
+ }
998
1059
  async collectIdfv() {
999
1060
  const RETRY_DELAY_MS = 80;
1000
1061
  const MAX_ATTEMPTS = 3;
@@ -1601,13 +1662,13 @@ var init_deferredAppLink = __esm({
1601
1662
  });
1602
1663
 
1603
1664
  // src/domains/identity/MetaBridge.ts
1604
- import { NativeModules as NativeModules2 } from "react-native";
1665
+ import { NativeModules as NativeModules3 } from "react-native";
1605
1666
  var TIMEOUT_MS, NativeBridge, MetaBridge, metaBridge;
1606
1667
  var init_MetaBridge = __esm({
1607
1668
  "src/domains/identity/MetaBridge.ts"() {
1608
1669
  "use strict";
1609
1670
  TIMEOUT_MS = 2e3;
1610
- NativeBridge = NativeModules2.PaywalloFBBridge ?? null;
1671
+ NativeBridge = NativeModules3.PaywalloFBBridge ?? null;
1611
1672
  MetaBridge = class {
1612
1673
  constructor() {
1613
1674
  this.cachedAnonId = null;
@@ -1940,6 +2001,7 @@ var init_InstallTracker = __esm({
1940
2001
  } else {
1941
2002
  const { generateUUID: generateUUID2 } = await Promise.resolve().then(() => (init_uuid(), uuid_exports));
1942
2003
  effectiveAnonId = `PW_${generateUUID2()}`;
2004
+ if (this.debug) console.log("[Paywallo] fb_anon_id: gerado PW_ local (Facebook Android SDK ausente no host? _fbp real indispon\xEDvel \u2014 Meta n\xE3o reconhece PW_)");
1943
2005
  await storage.set(INSTALL_KEYS.ANON_ID, effectiveAnonId).catch(() => {
1944
2006
  });
1945
2007
  }
@@ -1968,11 +2030,11 @@ var init_InstallTracker = __esm({
1968
2030
  ...adIds.gaid && { gaid: adIds.gaid },
1969
2031
  attStatus: adIds.attStatus
1970
2032
  }, void 0, { priority: "critical" });
1971
- void this.callDeferredMatch(apiClient, deviceData, adIds, effectiveAnonId, installedAt).catch(() => {
2033
+ void this.callDeferredMatch(apiClient, distinctId, deviceData, adIds, effectiveAnonId, installedAt).catch(() => {
1972
2034
  });
1973
2035
  await markInstallTracked(storage, installedAt);
1974
2036
  }
1975
- async callDeferredMatch(apiClient, deviceData, adIds, anonId, installedAt) {
2037
+ async callDeferredMatch(apiClient, distinctId, deviceData, adIds, anonId, installedAt) {
1976
2038
  const storage = new SecureStorage(this.debug);
1977
2039
  const alreadyMatched = await storage.get(INSTALL_KEYS.DEFERRED_MATCH_DONE);
1978
2040
  if (alreadyMatched) return;
@@ -1987,6 +2049,10 @@ var init_InstallTracker = __esm({
1987
2049
  headers: { "Content-Type": "application/json", "X-App-Key": appKey },
1988
2050
  body: JSON.stringify({
1989
2051
  platform: Platform4.OS,
2052
+ // Sem isto o servidor não tem identificador no Android (não há IDFV) e grava a
2053
+ // attribution com distinct_id vazio — o reader junta por
2054
+ // install_attributions.distinct_id = app_users.external_id e nunca casa.
2055
+ distinctId,
1990
2056
  ...adIds.idfv && { idfv: adIds.idfv },
1991
2057
  ...adIds.gaid && { gaid: adIds.gaid },
1992
2058
  ...referrer.rawReferrer && { installReferrer: referrer.rawReferrer },
@@ -2147,12 +2213,12 @@ var init_identity = __esm({
2147
2213
  });
2148
2214
 
2149
2215
  // src/domains/notifications/bridges/NativePushBridge.ts
2150
- import { NativeEventEmitter, NativeModules as NativeModules3, Platform as Platform5 } from "react-native";
2216
+ import { NativeEventEmitter, NativeModules as NativeModules4, Platform as Platform5 } from "react-native";
2151
2217
  function getPaywalloNotifications() {
2152
- return NativeModules3.PaywalloNotifications ?? null;
2218
+ return NativeModules4.PaywalloNotifications ?? null;
2153
2219
  }
2154
2220
  function isNativePushAvailable() {
2155
- return !!NativeModules3.PaywalloNotifications;
2221
+ return !!NativeModules4.PaywalloNotifications;
2156
2222
  }
2157
2223
  function mapStatusToNumber(status) {
2158
2224
  switch (status) {
@@ -2174,7 +2240,7 @@ function mapStatusToNumber(status) {
2174
2240
  }
2175
2241
  function getEmitter() {
2176
2242
  if (_emitter) return _emitter;
2177
- const nativeMod = NativeModules3.PaywalloNotifications;
2243
+ const nativeMod = NativeModules4.PaywalloNotifications;
2178
2244
  if (!nativeMod) return null;
2179
2245
  _emitter = new NativeEventEmitter(nativeMod);
2180
2246
  return _emitter;
@@ -2611,8 +2677,8 @@ var init_NotificationHandlerSetup = __esm({
2611
2677
  // src/core/version.ts
2612
2678
  function resolveVersion() {
2613
2679
  try {
2614
- if ("2.6.0") {
2615
- return "2.6.0";
2680
+ if ("2.6.2") {
2681
+ return "2.6.2";
2616
2682
  }
2617
2683
  } catch {
2618
2684
  }
@@ -3610,7 +3676,7 @@ var init_paywallHeartbeat = __esm({
3610
3676
  });
3611
3677
 
3612
3678
  // src/utils/localization.ts
3613
- import { NativeModules as NativeModules4, Platform as Platform9 } from "react-native";
3679
+ import { NativeModules as NativeModules5, Platform as Platform9 } from "react-native";
3614
3680
  function setCurrentLanguage(language) {
3615
3681
  currentLanguage = language;
3616
3682
  }
@@ -3631,10 +3697,10 @@ function getLocalizedString(text) {
3631
3697
  function detectDeviceLanguage() {
3632
3698
  try {
3633
3699
  if (Platform9.OS === "ios") {
3634
- const settings = NativeModules4.SettingsManager?.settings;
3700
+ const settings = NativeModules5.SettingsManager?.settings;
3635
3701
  return settings?.AppleLocale ?? settings?.AppleLanguages?.[0] ?? "en-US";
3636
3702
  }
3637
- return NativeModules4.I18nManager?.localeIdentifier ?? "en-US";
3703
+ return NativeModules5.I18nManager?.localeIdentifier ?? "en-US";
3638
3704
  } catch {
3639
3705
  return "en-US";
3640
3706
  }
@@ -3805,7 +3871,7 @@ import {
3805
3871
  findNodeHandle,
3806
3872
  Linking as Linking2,
3807
3873
  NativeEventEmitter as NativeEventEmitter2,
3808
- NativeModules as NativeModules5,
3874
+ NativeModules as NativeModules6,
3809
3875
  Platform as Platform10,
3810
3876
  requireNativeComponent,
3811
3877
  StyleSheet as StyleSheet2,
@@ -3826,7 +3892,7 @@ function getNativeWebView() {
3826
3892
  }
3827
3893
  function getWebViewEmitter() {
3828
3894
  if (webViewEmitter) return webViewEmitter;
3829
- const mod = NativeModules5.PaywalloWebViewModule;
3895
+ const mod = NativeModules6.PaywalloWebViewModule;
3830
3896
  if (!mod) return null;
3831
3897
  webViewEmitter = new NativeEventEmitter2(mod);
3832
3898
  return webViewEmitter;
@@ -4160,7 +4226,7 @@ __export(NativeStoreKit_exports, {
4160
4226
  NativeStoreKit: () => NativeStoreKit,
4161
4227
  nativeStoreKit: () => nativeStoreKit
4162
4228
  });
4163
- import { NativeEventEmitter as NativeEventEmitter3, NativeModules as NativeModules6, Platform as Platform11 } from "react-native";
4229
+ import { NativeEventEmitter as NativeEventEmitter3, NativeModules as NativeModules7, Platform as Platform11 } from "react-native";
4164
4230
  function isAvailable3() {
4165
4231
  return PaywalloStoreKitNative != null;
4166
4232
  }
@@ -4262,7 +4328,7 @@ var init_NativeStoreKit = __esm({
4262
4328
  init_IdentityManager();
4263
4329
  init_PurchaseError();
4264
4330
  TRANSACTION_UPDATE_EVENT = "PaywalloTransactionUpdate";
4265
- PaywalloStoreKitNative = NativeModules6.PaywalloStoreKit ?? null;
4331
+ PaywalloStoreKitNative = NativeModules7.PaywalloStoreKit ?? null;
4266
4332
  nativeStoreKit = {
4267
4333
  isAvailable: isAvailable3,
4268
4334
  async getProducts(productIds) {
@@ -7334,19 +7400,19 @@ var init_SubscriptionManager = __esm({
7334
7400
  });
7335
7401
 
7336
7402
  // src/utils/detectEnvironment.ts
7337
- import { NativeModules as NativeModules7 } from "react-native";
7403
+ import { NativeModules as NativeModules8 } from "react-native";
7338
7404
  async function detectEnvironment() {
7339
7405
  if (cached !== null) return cached;
7340
7406
  if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
7341
7407
  cached = "sandbox";
7342
7408
  return cached;
7343
7409
  }
7344
- if (!nativeModule) {
7410
+ if (!nativeModule2) {
7345
7411
  cached = "production";
7346
7412
  return cached;
7347
7413
  }
7348
7414
  try {
7349
- const result = await nativeModule.detect();
7415
+ const result = await nativeModule2.detect();
7350
7416
  cached = result === "sandbox" ? "sandbox" : "production";
7351
7417
  return cached;
7352
7418
  } catch {
@@ -7354,11 +7420,11 @@ async function detectEnvironment() {
7354
7420
  return cached;
7355
7421
  }
7356
7422
  }
7357
- var nativeModule, cached;
7423
+ var nativeModule2, cached;
7358
7424
  var init_detectEnvironment = __esm({
7359
7425
  "src/utils/detectEnvironment.ts"() {
7360
7426
  "use strict";
7361
- nativeModule = NativeModules7.PaywalloEnv ?? null;
7427
+ nativeModule2 = NativeModules8.PaywalloEnv ?? null;
7362
7428
  cached = null;
7363
7429
  }
7364
7430
  });
@@ -7426,6 +7492,31 @@ var init_apiPurchaseMethods = __esm({
7426
7492
  }
7427
7493
  });
7428
7494
 
7495
+ // src/utils/userAgent.ts
7496
+ import { Platform as Platform14 } from "react-native";
7497
+ function buildUserAgent(sdkVersion) {
7498
+ const clean = (v) => v.replace(/[^\x20-\x7E]/g, "").replace(/[();]/g, "").trim();
7499
+ const info = typeof nativeDeviceInfo.getCachedDeviceInfo === "function" ? nativeDeviceInfo.getCachedDeviceInfo() : null;
7500
+ if (!info) {
7501
+ return `PaywalloSDK/${sdkVersion} (${clean(Platform14.OS)})`;
7502
+ }
7503
+ const isValid = (v) => {
7504
+ if (typeof v !== "string") return false;
7505
+ const c = clean(v);
7506
+ return c.length > 0 && c !== "unknown";
7507
+ };
7508
+ const parts = [clean(info.osName)];
7509
+ if (isValid(info.systemVersion)) parts.push(clean(info.systemVersion));
7510
+ const detail = isValid(info.model) ? `; ${clean(info.model)}` : "";
7511
+ return `PaywalloSDK/${sdkVersion} (${parts.join(" ")}${detail})`;
7512
+ }
7513
+ var init_userAgent = __esm({
7514
+ "src/utils/userAgent.ts"() {
7515
+ "use strict";
7516
+ init_NativeDeviceInfo();
7517
+ }
7518
+ });
7519
+
7429
7520
  // src/core/ApiCache.ts
7430
7521
  var ApiCache;
7431
7522
  var init_ApiCache = __esm({
@@ -7669,6 +7760,11 @@ async function postWithQueue(deps, url, payload, label, priority) {
7669
7760
  priority
7670
7761
  );
7671
7762
  };
7763
+ if (priority === "critical" && deps.isOfflineQueueEnabled()) {
7764
+ await enqueue();
7765
+ if (deps.isDebug()) console.log("[Paywallo:ApiClient] Critical event queued (write-ahead):", label);
7766
+ return;
7767
+ }
7672
7768
  if (deps.isOfflineQueueEnabled() && !networkMonitor.isOnline()) {
7673
7769
  await enqueue();
7674
7770
  if (deps.isDebug()) console.log("[Paywallo:ApiClient] Queued for offline:", label, priority ?? "normal");
@@ -7701,7 +7797,7 @@ var init_ApiClientQueue = __esm({
7701
7797
  });
7702
7798
 
7703
7799
  // src/core/eventEnvelopeV2.ts
7704
- import { Platform as Platform14 } from "react-native";
7800
+ import { Platform as Platform15 } from "react-native";
7705
7801
  import { z as z2 } from "zod";
7706
7802
  function buildV2Envelope(events, providerContext) {
7707
7803
  const context = { ...providerContext };
@@ -7728,7 +7824,7 @@ function buildV2Envelope(events, providerContext) {
7728
7824
  return { id, ts: event.timestamp, name: family, payload };
7729
7825
  });
7730
7826
  if (context.sdk_version === void 0) context.sdk_version = SDK_VERSION;
7731
- if (context.platform === void 0) context.platform = Platform14.OS;
7827
+ if (context.platform === void 0) context.platform = Platform15.OS;
7732
7828
  if (context.distinct_id === void 0 && events.length > 0) {
7733
7829
  context.distinct_id = events[0].distinctId;
7734
7830
  }
@@ -7866,7 +7962,7 @@ var init_events = __esm({
7866
7962
  });
7867
7963
 
7868
7964
  // src/core/EventBatcher.ts
7869
- import { Platform as Platform15 } from "react-native";
7965
+ import { Platform as Platform16 } from "react-native";
7870
7966
  var BATCH_MAX_SIZE, BATCH_FLUSH_MS, EVENT_NAME_REGEX, V2_BATCH_ENDPOINT, EventBatcher;
7871
7967
  var init_EventBatcher = __esm({
7872
7968
  "src/core/EventBatcher.ts"() {
@@ -7879,10 +7975,8 @@ var init_EventBatcher = __esm({
7879
7975
  V2_BATCH_ENDPOINT = "/sdk/ingest/batch";
7880
7976
  EventBatcher = class {
7881
7977
  constructor(post, debug = false, contextProvider = null) {
7882
- this.criticalQueue = [];
7883
7978
  this.normalQueue = [];
7884
7979
  this.normalTimer = null;
7885
- this.criticalScheduled = false;
7886
7980
  this.post = post;
7887
7981
  this.debug = debug;
7888
7982
  this.contextProvider = contextProvider;
@@ -7919,14 +8013,17 @@ var init_EventBatcher = __esm({
7919
8013
  const event = {
7920
8014
  eventName,
7921
8015
  distinctId,
7922
- properties: { ...properties, platform: Platform15.OS },
8016
+ properties: { ...properties, platform: Platform16.OS },
7923
8017
  timestamp: timestamp ?? Date.now(),
7924
8018
  environment: environment.toLowerCase()
7925
8019
  };
7926
8020
  const priority = options?.priority ?? "normal";
7927
8021
  if (priority === "critical") {
7928
- this.criticalQueue.push(event);
7929
- this.scheduleCriticalFlush();
8022
+ try {
8023
+ await this.postBatch([event], `event_critical:${event.eventName}`, "critical");
8024
+ } catch (err) {
8025
+ if (this.debug) console.log("[Paywallo:CRITICAL] critical event post failed", { eventName: event.eventName, error: err instanceof Error ? err.message : String(err) });
8026
+ }
7930
8027
  return;
7931
8028
  }
7932
8029
  this.normalQueue.push(event);
@@ -7947,9 +8044,10 @@ var init_EventBatcher = __esm({
7947
8044
  }
7948
8045
  /**
7949
8046
  * Force flush of the normal queue. Critical events are never held in the
7950
- * normal queue, so this does not affect them (they flush on their own
7951
- * microtask). Exposed so callers (e.g. `AppState=background` listener in
7952
- * phase 2.4) can drain pending events before the app is suspended.
8047
+ * normal queue, so this does not affect them they are posted (and
8048
+ * awaited) synchronously inside `track()`. Exposed so callers (e.g.
8049
+ * `AppState=background` listener in phase 2.4) can drain pending events
8050
+ * before the app is suspended.
7953
8051
  */
7954
8052
  async flush() {
7955
8053
  await this.flushNormal();
@@ -7959,28 +8057,7 @@ var init_EventBatcher = __esm({
7959
8057
  clearTimeout(this.normalTimer);
7960
8058
  this.normalTimer = null;
7961
8059
  }
7962
- this.criticalQueue = [];
7963
8060
  this.normalQueue = [];
7964
- this.criticalScheduled = false;
7965
- }
7966
- scheduleCriticalFlush() {
7967
- if (this.criticalScheduled) return;
7968
- this.criticalScheduled = true;
7969
- queueMicrotask(() => {
7970
- this.criticalScheduled = false;
7971
- void this.flushCritical();
7972
- });
7973
- }
7974
- async flushCritical() {
7975
- if (this.criticalQueue.length === 0) return;
7976
- const drained = this.criticalQueue.splice(0, this.criticalQueue.length);
7977
- for (const event of drained) {
7978
- try {
7979
- await this.postBatch([event], `event_critical:${event.eventName}`, "critical");
7980
- } catch (err) {
7981
- if (this.debug) console.log("[Paywallo:CRITICAL] critical event post failed", { eventName: event.eventName, error: err instanceof Error ? err.message : String(err) });
7982
- }
7983
- }
7984
8061
  }
7985
8062
  async flushNormal() {
7986
8063
  if (this.normalQueue.length === 0) return;
@@ -8245,7 +8322,7 @@ var init_http = __esm({
8245
8322
  });
8246
8323
 
8247
8324
  // src/core/ApiClient.ts
8248
- import { Platform as Platform16 } from "react-native";
8325
+ import { Platform as Platform17 } from "react-native";
8249
8326
  function normalizeDateOfBirth(raw) {
8250
8327
  if (!raw) return void 0;
8251
8328
  if (DATE_OF_BIRTH_RE.test(raw)) return raw;
@@ -8266,6 +8343,7 @@ function buildPiiPayload(pii) {
8266
8343
  if (dob) result.dateOfBirth = dob;
8267
8344
  const g = normalizeGender(pii.gender);
8268
8345
  if (g) result.gender = g;
8346
+ if (pii.zipCode) result.zipCode = pii.zipCode.trim();
8269
8347
  return result;
8270
8348
  }
8271
8349
  function normalizeGender(raw) {
@@ -8280,6 +8358,7 @@ var init_ApiClient = __esm({
8280
8358
  "src/core/ApiClient.ts"() {
8281
8359
  "use strict";
8282
8360
  init_apiPurchaseMethods();
8361
+ init_userAgent();
8283
8362
  init_ApiCache();
8284
8363
  init_ApiClientFlags();
8285
8364
  init_ApiClientQueue();
@@ -8379,10 +8458,13 @@ var init_ApiClient = __esm({
8379
8458
  * should carry. Keep this tiny — it runs once per ApiClient instance.
8380
8459
  */
8381
8460
  buildSdkHeaders() {
8461
+ const ua = buildUserAgent(SDK_VERSION);
8382
8462
  return {
8383
8463
  "x-sdk-version": SDK_VERSION,
8384
- "x-sdk-platform": Platform16.OS,
8385
- "x-sdk-environment": this.environment
8464
+ "x-sdk-platform": Platform17.OS,
8465
+ "x-sdk-environment": this.environment,
8466
+ "User-Agent": ua,
8467
+ "x-sdk-user-agent": ua
8386
8468
  };
8387
8469
  }
8388
8470
  async clearQueue() {
@@ -8411,7 +8493,7 @@ var init_ApiClient = __esm({
8411
8493
  message,
8412
8494
  context,
8413
8495
  sdkVersion: SDK_VERSION,
8414
- platform: Platform16.OS
8496
+ platform: Platform17.OS
8415
8497
  }, true);
8416
8498
  } catch (err) {
8417
8499
  if (this.debug) console.log("[Paywallo:ApiClient] reportError failed", err);
@@ -8429,7 +8511,7 @@ var init_ApiClient = __esm({
8429
8511
  async identify(distinctId, properties, email, deviceId, pii) {
8430
8512
  const rawTraits = {
8431
8513
  email: email || void 0,
8432
- platform: Platform16.OS,
8514
+ platform: Platform17.OS,
8433
8515
  name: properties?.name,
8434
8516
  country: properties?.country,
8435
8517
  locale: properties?.locale,
@@ -8841,9 +8923,14 @@ async function doInit(state, config) {
8841
8923
  } catch (err) {
8842
8924
  if (config.debug) console.log("[Paywallo ATTR] start error", err);
8843
8925
  }
8844
- void nativeDeviceInfo.getDeviceInfo().catch(() => null);
8845
- void advertisingIdManager.collect(false).catch(() => null);
8846
- void metaBridge.getAnonymousID().catch(() => null);
8926
+ await Promise.race([
8927
+ Promise.all([
8928
+ nativeDeviceInfo.getDeviceInfo().catch(() => null),
8929
+ advertisingIdManager.collect(false).catch(() => null),
8930
+ metaBridge.getAnonymousID().catch(() => null)
8931
+ ]),
8932
+ new Promise((resolve) => setTimeout(resolve, 350))
8933
+ ]);
8847
8934
  apiClient.setEventContextProvider(() => {
8848
8935
  const attr = attributionTracker.get();
8849
8936
  const attrEntries = attr ? [
@@ -9396,9 +9483,9 @@ __export(OfferingService_exports, {
9396
9483
  OfferingService: () => OfferingService,
9397
9484
  offeringService: () => offeringService
9398
9485
  });
9399
- import { Platform as Platform17 } from "react-native";
9486
+ import { Platform as Platform18 } from "react-native";
9400
9487
  function resolveProductId(raw) {
9401
- const isIos = Platform17.OS === "ios";
9488
+ const isIos = Platform18.OS === "ios";
9402
9489
  const productId = isIos ? raw.apple_product_id : raw.google_product_id;
9403
9490
  return productId ?? "";
9404
9491
  }
@@ -9417,7 +9504,7 @@ function mapProduct2(raw) {
9417
9504
  };
9418
9505
  }
9419
9506
  function pickPlatformProduct(products) {
9420
- const isIos = Platform17.OS === "ios";
9507
+ const isIos = Platform18.OS === "ios";
9421
9508
  const match = products.find((p) => isIos ? p.apple_product_id : p.google_product_id);
9422
9509
  return match ?? products[0] ?? null;
9423
9510
  }