@wireai/activation 0.11.0 → 0.12.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.
Files changed (73) hide show
  1. package/AGENTS.md +62 -8
  2. package/CHANGELOG.md +188 -3
  3. package/INTEGRATION_PROMPT.md +25 -2
  4. package/README.md +112 -1
  5. package/dist/analytics/index.d.mts +18 -6
  6. package/dist/analytics/index.d.ts +18 -6
  7. package/dist/analytics/index.js +151 -41
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +147 -42
  10. package/dist/analytics/index.mjs.map +1 -1
  11. package/dist/coachmarks/index.d.mts +16 -0
  12. package/dist/coachmarks/index.d.ts +16 -0
  13. package/dist/coachmarks/index.js +19 -13
  14. package/dist/coachmarks/index.js.map +1 -1
  15. package/dist/coachmarks/index.mjs +19 -13
  16. package/dist/coachmarks/index.mjs.map +1 -1
  17. package/dist/{currentSession-C0_odnIW.d.mts → currentSession-BlCeDP0f.d.mts} +145 -33
  18. package/dist/{currentSession-DdnUq2HQ.d.ts → currentSession-BxEB37xt.d.ts} +145 -33
  19. package/dist/index.d.mts +243 -53
  20. package/dist/index.d.ts +243 -53
  21. package/dist/index.js +531 -156
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +517 -157
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/questionnaire/index.d.mts +1 -1
  26. package/dist/questionnaire/index.d.ts +1 -1
  27. package/dist/questionnaire/index.js +79 -14
  28. package/dist/questionnaire/index.js.map +1 -1
  29. package/dist/questionnaire/index.mjs +79 -14
  30. package/dist/questionnaire/index.mjs.map +1 -1
  31. package/dist/reviews/index.d.mts +2 -2
  32. package/dist/reviews/index.d.ts +2 -2
  33. package/dist/reviews/index.js +103 -16
  34. package/dist/reviews/index.js.map +1 -1
  35. package/dist/reviews/index.mjs +103 -16
  36. package/dist/reviews/index.mjs.map +1 -1
  37. package/dist/showcase/index.js +15 -6
  38. package/dist/showcase/index.js.map +1 -1
  39. package/dist/showcase/index.mjs +15 -6
  40. package/dist/showcase/index.mjs.map +1 -1
  41. package/dist/{transport-BGW9uXZJ.d.mts → transport-CF_eHwzC.d.mts} +15 -1
  42. package/dist/{transport-jUJd5kxu.d.ts → transport-DsRe4epC.d.ts} +15 -1
  43. package/llms.txt +3 -0
  44. package/package.json +1 -1
  45. package/src/WireOnboarding.tsx +140 -5
  46. package/src/activation/useWireActivation.ts +12 -1
  47. package/src/activation/wireActivation.ts +44 -25
  48. package/src/analytics/analyticsFacade.ts +54 -29
  49. package/src/analytics/currentSession.ts +83 -0
  50. package/src/analytics/eventQueue.ts +9 -1
  51. package/src/analytics/index.ts +20 -1
  52. package/src/analytics/reportClientEvent.ts +42 -0
  53. package/src/analytics/screenTracking.ts +6 -1
  54. package/src/analytics/useAnalytics.ts +22 -1
  55. package/src/coachmarks/runtime.ts +53 -17
  56. package/src/config/wireConfigFromEnv.ts +46 -2
  57. package/src/context/deviceId.ts +173 -0
  58. package/src/context/userContext.ts +18 -0
  59. package/src/index.ts +54 -2
  60. package/src/questionnaire/runtime.ts +13 -2
  61. package/src/questionnaire/useQuestionnaireGate.ts +11 -4
  62. package/src/revenuecat/index.ts +55 -0
  63. package/src/revenuecat/purchaseEvents.ts +167 -0
  64. package/src/revenuecat/revenueCatBridge.ts +221 -0
  65. package/src/revenuecat/types.ts +95 -0
  66. package/src/reviews/runtime.ts +153 -1
  67. package/src/reviews/transport.ts +21 -2
  68. package/src/reviews/useReviewGate.ts +14 -4
  69. package/src/session-analytics/lifecycle.ts +9 -2
  70. package/src/session-analytics/reportSessionStart.ts +15 -4
  71. package/src/session-analytics/useLifecycleEvents.ts +83 -27
  72. package/src/session-analytics/useSessionStart.ts +37 -1
  73. package/src/types.ts +41 -4
package/dist/index.mjs CHANGED
@@ -1512,6 +1512,23 @@ var buildEventsRequest = (target, events) => {
1512
1512
  return null;
1513
1513
  }
1514
1514
  };
1515
+ var warnOnSkippedEvents = (res) => {
1516
+ if (typeof __DEV__ === "undefined" || !__DEV__) return;
1517
+ if (typeof console === "undefined" || !console.warn) return;
1518
+ try {
1519
+ const json = res == null ? void 0 : res.json;
1520
+ if (typeof json !== "function") return;
1521
+ void Promise.resolve(json.call(res)).then((body) => {
1522
+ const skipped = body == null ? void 0 : body.skipped;
1523
+ if (typeof skipped !== "number" || skipped <= 0) return;
1524
+ console.warn(
1525
+ `[wireai] the server ACCEPTED the /v1/events POST but DISCARDED ${skipped} event(s) (skipped in the response body) \u2014 they are gone, not retried. The usual cause is an event with a missing or empty session_id.`
1526
+ );
1527
+ }).catch(() => {
1528
+ });
1529
+ } catch {
1530
+ }
1531
+ };
1515
1532
  var reportClientEvents = (target, events) => {
1516
1533
  try {
1517
1534
  const req = buildEventsRequest(target, events);
@@ -3294,6 +3311,82 @@ var collectDeviceContext = () => {
3294
3311
  return ctx;
3295
3312
  };
3296
3313
 
3314
+ // src/context/deviceId.ts
3315
+ var AUTO_DEVICE_ID_PREFIX = "wdev_";
3316
+ var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
3317
+ var randomChunk = () => Math.floor(Math.random() * 4294967296).toString(36).padStart(6, "0");
3318
+ var mintDeviceId = () => {
3319
+ const time = Date.now().toString(36);
3320
+ return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
3321
+ };
3322
+ var AUTO_DEVICE_KEY_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:autoDeviceKeys");
3323
+ var deviceKeyGlobal = globalThis;
3324
+ var autoDeviceKeyRegistry = () => {
3325
+ const existing = deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT];
3326
+ if (existing) return existing;
3327
+ const created = { keys: /* @__PURE__ */ new Map(), hydrating: /* @__PURE__ */ new Set() };
3328
+ deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT] = created;
3329
+ return created;
3330
+ };
3331
+ var startHydration = (registry, appId, storage, minted) => {
3332
+ if (!registry.pending) registry.pending = /* @__PURE__ */ new Map();
3333
+ const existing = registry.pending.get(appId);
3334
+ if (existing) return existing;
3335
+ const slot = deviceIdStorageKey(appId);
3336
+ const settled = () => {
3337
+ var _a2;
3338
+ return (_a2 = registry.keys.get(appId)) != null ? _a2 : minted;
3339
+ };
3340
+ let run;
3341
+ try {
3342
+ run = Promise.resolve(storage.getItem(slot)).then((saved) => {
3343
+ const persisted = typeof saved === "string" && saved.trim() ? saved.trim() : void 0;
3344
+ if (persisted) {
3345
+ registry.keys.set(appId, persisted);
3346
+ return persisted;
3347
+ }
3348
+ return Promise.resolve(storage.setItem(slot, minted)).then(settled, settled);
3349
+ }).catch(settled);
3350
+ } catch {
3351
+ run = Promise.resolve(settled());
3352
+ }
3353
+ registry.pending.set(appId, run);
3354
+ return run;
3355
+ };
3356
+ var resolveAutoDeviceKey = (opts = {}) => {
3357
+ var _a2, _b;
3358
+ const registry = autoDeviceKeyRegistry();
3359
+ const appId = (_a2 = opts.appId) != null ? _a2 : "default";
3360
+ let id = registry.keys.get(appId);
3361
+ if (!id) {
3362
+ id = mintDeviceId();
3363
+ registry.keys.set(appId, id);
3364
+ }
3365
+ const storage = opts.storage;
3366
+ if (storage && !registry.hydrating.has(appId)) {
3367
+ registry.hydrating.add(appId);
3368
+ void startHydration(registry, appId, storage, id);
3369
+ }
3370
+ return (_b = registry.keys.get(appId)) != null ? _b : id;
3371
+ };
3372
+ var hydrateAutoDeviceKey = async (opts = {}) => {
3373
+ var _a2, _b, _c;
3374
+ const id = resolveAutoDeviceKey(opts);
3375
+ if (!opts.storage) return id;
3376
+ const registry = autoDeviceKeyRegistry();
3377
+ const appId = (_a2 = opts.appId) != null ? _a2 : "default";
3378
+ const pending = (_b = registry.pending) == null ? void 0 : _b.get(appId);
3379
+ if (pending) await pending;
3380
+ return (_c = registry.keys.get(appId)) != null ? _c : id;
3381
+ };
3382
+ var resetAutoDeviceKeys = () => {
3383
+ var _a2;
3384
+ const registry = autoDeviceKeyRegistry();
3385
+ registry.keys.clear();
3386
+ registry.hydrating.clear();
3387
+ (_a2 = registry.pending) == null ? void 0 : _a2.clear();
3388
+ };
3389
+
3297
3390
  // src/analytics/currentSession.ts
3298
3391
  var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
3299
3392
  "@wireai/activation:currentSessionId"
@@ -3308,6 +3401,28 @@ var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
3308
3401
  var resetCurrentSessionId = () => {
3309
3402
  globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
3310
3403
  };
3404
+ var warnInDev = (message) => {
3405
+ if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
3406
+ console.warn(message);
3407
+ return true;
3408
+ }
3409
+ return false;
3410
+ };
3411
+ var MINT_WARNING = "[wireai] No app-open session was registered, so a session id was minted for this event (the server drops an event that has no session_id, and still answers 200). Mount useLifecycleEvents at your app root so events correlate to a real app-open.";
3412
+ var MINT_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
3413
+ "@wireai/activation:currentSessionIdMintWarned"
3414
+ );
3415
+ var warnSlot = globalThis;
3416
+ var ensureCurrentSessionId = () => {
3417
+ const existing = globalSlot[CURRENT_SESSION_ID_SLOT];
3418
+ if (typeof existing === "string" && existing.length > 0) return existing;
3419
+ const minted = makeSessionId();
3420
+ globalSlot[CURRENT_SESSION_ID_SLOT] = minted;
3421
+ if (!warnSlot[MINT_WARNED_SLOT] && warnInDev(MINT_WARNING)) {
3422
+ warnSlot[MINT_WARNED_SLOT] = true;
3423
+ }
3424
+ return minted;
3425
+ };
3311
3426
 
3312
3427
  // src/session/persistedSession.ts
3313
3428
  var DEFAULT_SESSION_TTL_MS = 36e5;
@@ -3397,6 +3512,105 @@ var identifyOnboarding = async (opts) => {
3397
3512
  );
3398
3513
  return true;
3399
3514
  };
3515
+
3516
+ // src/context/userContext.ts
3517
+ var RESERVED_USER_CONTEXT_KEYS = [
3518
+ "device_key",
3519
+ "app_version",
3520
+ "app_build",
3521
+ "network_type",
3522
+ "session_count",
3523
+ "returning",
3524
+ "platform",
3525
+ "user_email",
3526
+ "user_email_hashed"
3527
+ ];
3528
+ var EXTRA_KEY_PREFIX = "custom.";
3529
+ var isWireScalar = (value) => {
3530
+ const t = typeof value;
3531
+ if (t === "string" || t === "boolean") return true;
3532
+ if (t === "number") return Number.isFinite(value);
3533
+ return false;
3534
+ };
3535
+ var hashEmailFnv1a = (email) => {
3536
+ const normalized = email.trim().toLowerCase();
3537
+ let hash = 2166136261;
3538
+ for (let i = 0; i < normalized.length; i++) {
3539
+ hash ^= normalized.charCodeAt(i);
3540
+ hash = Math.imul(hash, 16777619);
3541
+ }
3542
+ return (hash >>> 0).toString(16).padStart(8, "0");
3543
+ };
3544
+ var cleanString = (value) => {
3545
+ if (typeof value !== "string") return void 0;
3546
+ const trimmed = value.trim();
3547
+ return trimmed.length > 0 ? trimmed : void 0;
3548
+ };
3549
+ var namespaceExtra = (extra) => {
3550
+ const out = {};
3551
+ if (!extra || typeof extra !== "object") return out;
3552
+ for (const [key, value] of Object.entries(extra)) {
3553
+ const cleanKey = cleanString(key);
3554
+ if (!cleanKey) continue;
3555
+ if (!isWireScalar(value)) continue;
3556
+ out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
3557
+ }
3558
+ return out;
3559
+ };
3560
+ var analyticsUserIdStorageKey = (appId) => `wireai:analytics:userId:${appId != null ? appId : "default"}`;
3561
+ var clearPiiFromContext = (ctx = {}) => {
3562
+ const rest = {};
3563
+ if (typeof ctx.appVersion === "string") rest.appVersion = ctx.appVersion;
3564
+ if (typeof ctx.deviceKey === "string") rest.deviceKey = ctx.deviceKey;
3565
+ return rest;
3566
+ };
3567
+ var clearUserContext = async (opts = {}) => {
3568
+ const storage = opts.storage;
3569
+ if (!storage) return;
3570
+ try {
3571
+ await storage.removeItem(analyticsUserIdStorageKey(opts.appId));
3572
+ } catch {
3573
+ }
3574
+ };
3575
+ var activationJoinContext = (deviceKey) => {
3576
+ var _a2;
3577
+ return (_a2 = resolveUserContext({ deviceKey }).userContext) != null ? _a2 : {};
3578
+ };
3579
+ var resolveUserContext = (ctx = {}, opts = {}) => {
3580
+ var _a2;
3581
+ const result = {};
3582
+ const bucket = {};
3583
+ const userId = sanitizeUserId(ctx.userId);
3584
+ if (userId) result.userId = userId;
3585
+ const deviceKey = cleanString(ctx.deviceKey);
3586
+ if (deviceKey) {
3587
+ result.deviceKey = deviceKey;
3588
+ bucket.device_key = deviceKey;
3589
+ }
3590
+ const appVersion = (_a2 = cleanString(ctx.appVersion)) != null ? _a2 : cleanString(opts.autoAppVersion);
3591
+ if (appVersion) {
3592
+ result.appVersion = appVersion;
3593
+ bucket.app_version = appVersion;
3594
+ }
3595
+ const email = cleanString(ctx.userEmail);
3596
+ if (email) {
3597
+ if (ctx.hashEmail) {
3598
+ bucket.user_email = hashEmailFnv1a(email);
3599
+ bucket.user_email_hashed = true;
3600
+ } else {
3601
+ bucket.user_email = email;
3602
+ }
3603
+ }
3604
+ Object.assign(bucket, namespaceExtra(ctx.extra));
3605
+ if (Object.keys(bucket).length > 0) result.userContext = bucket;
3606
+ return result;
3607
+ };
3608
+ var warnInDev2 = (message) => {
3609
+ if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
3610
+ console.warn(message);
3611
+ }
3612
+ };
3613
+ var AUTO_JOIN_HYDRATION_TIMEOUT_MS = 1500;
3400
3614
  var WireOnboarding = ({
3401
3615
  config,
3402
3616
  theme,
@@ -3419,7 +3633,8 @@ var WireOnboarding = ({
3419
3633
  persistKey,
3420
3634
  retainSessionOnComplete,
3421
3635
  userContext,
3422
- userId
3636
+ userId,
3637
+ autoJoinKey = true
3423
3638
  }) => {
3424
3639
  var _a2, _b, _c;
3425
3640
  const boundUserId = useMemo(() => sanitizeUserId(userId), [userId]);
@@ -3432,9 +3647,50 @@ var WireOnboarding = ({
3432
3647
  () => userContextKey ? JSON.parse(userContextKey) : void 0,
3433
3648
  [userContextKey]
3434
3649
  );
3650
+ const missingJoinKey = typeof (userContextStable == null ? void 0 : userContextStable.device_key) !== "string" || !userContextStable.device_key.trim();
3651
+ const autoJoinPossible = Boolean(storage) && autoJoinKey !== false;
3652
+ const wantsAutoJoin = missingJoinKey && autoJoinPossible;
3653
+ const [autoJoinValue, setAutoJoinValue] = useState(void 0);
3654
+ useEffect(() => {
3655
+ if (!wantsAutoJoin || autoJoinValue !== void 0 || !storage) return;
3656
+ let cancelled = false;
3657
+ const timer = setTimeout(() => {
3658
+ if (!cancelled) setAutoJoinValue(null);
3659
+ }, AUTO_JOIN_HYDRATION_TIMEOUT_MS);
3660
+ void hydrateAutoDeviceKey({ appId: config.appId, storage }).then((key) => {
3661
+ if (cancelled) return;
3662
+ clearTimeout(timer);
3663
+ setAutoJoinValue(key || null);
3664
+ });
3665
+ return () => {
3666
+ cancelled = true;
3667
+ clearTimeout(timer);
3668
+ };
3669
+ }, [wantsAutoJoin, autoJoinValue, config.appId, storage]);
3670
+ const injectedJoinKey = wantsAutoJoin && typeof autoJoinValue === "string" ? autoJoinValue : void 0;
3671
+ const autoJoinPending = wantsAutoJoin && autoJoinValue === void 0;
3672
+ const effectiveUserContext = useMemo(
3673
+ () => injectedJoinKey ? { ...userContextStable, ...activationJoinContext(injectedJoinKey) } : userContextStable,
3674
+ [userContextStable, injectedJoinKey]
3675
+ );
3676
+ const warnMissingJoinKey = missingJoinKey && !injectedJoinKey && !autoJoinPending;
3677
+ const autoJoinReason = autoJoinKey === false ? "you passed autoJoinKey={false}." : !storage ? "it got no `storage` prop, and without persistence its key would be different on every launch, which corrupts min_sessions instead of merely leaving the join empty." : "your `storage` adapter did not answer in time.";
3678
+ useEffect(() => {
3679
+ if (!warnMissingJoinKey) return;
3680
+ warnInDev2(
3681
+ "[wireai] <WireOnboarding> got no user_context.device_key, so this onboarding session can never be joined to the app's later events and the `activated` funnel will read zero. Pass userContext={activationJoinContext(deviceKey)} \u2014 and if your app owns no device id, userContext={activationJoinContext(resolveAutoDeviceKey({ appId, storage }))} returns the SAME id the analytics side stamps. Never hand-write userContext={{ deviceKey }}. The kit did NOT auto-inject its own key here because " + autoJoinReason
3682
+ );
3683
+ }, [warnMissingJoinKey, autoJoinReason]);
3684
+ const misspelledJoinKey = missingJoinKey && typeof (userContextStable == null ? void 0 : userContextStable.deviceKey) === "string" && Boolean(userContextStable.deviceKey.trim());
3685
+ useEffect(() => {
3686
+ if (!misspelledJoinKey || !injectedJoinKey) return;
3687
+ warnInDev2(
3688
+ "[wireai] <WireOnboarding> got userContext={{ deviceKey }}, which is NOT the wire key \u2014 the server's device lookup reads `device_key`. The kit auto-injected its own device_key so this session is at least self-consistent, but your app's own events carry YOUR id, so the two still will not join and the `activated` funnel stays zero. Pass userContext={activationJoinContext(deviceKey)} instead."
3689
+ );
3690
+ }, [misspelledJoinKey, injectedJoinKey]);
3435
3691
  const clientContext = useMemo(
3436
- () => ({ device, userContext: userContextStable, userId: boundUserId }),
3437
- [device, userContextStable, boundUserId]
3692
+ () => ({ device, userContext: effectiveUserContext, userId: boundUserId }),
3693
+ [device, effectiveUserContext, boundUserId]
3438
3694
  );
3439
3695
  const [session, setSession] = useState(
3440
3696
  () => storage ? null : { id: makeSessionId(), resumed: false }
@@ -3481,7 +3737,7 @@ var WireOnboarding = ({
3481
3737
  // Device snapshot + host-injected user context ride the session-start metadata so the
3482
3738
  // backend can segment the funnel. Old servers ignore these unknown keys (backward compat).
3483
3739
  device,
3484
- ...userContextStable ? { userContext: userContextStable } : {},
3740
+ ...effectiveUserContext ? { userContext: effectiveUserContext } : {},
3485
3741
  // The session-start user id (from the ref) rides the session-start metadata so the
3486
3742
  // server binds the session to a real user at creation. Reading the ref — not
3487
3743
  // `boundUserId` — keeps this memo off the userId dependency, so a mid-session change
@@ -3490,7 +3746,7 @@ var WireOnboarding = ({
3490
3746
  },
3491
3747
  timeoutMs: 6e4
3492
3748
  };
3493
- }, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device, userContextStable]);
3749
+ }, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device, effectiveUserContext]);
3494
3750
  const reportTarget = useMemo(
3495
3751
  () => ({ serverUrl: config.serverUrl, apiKey: config.apiKey }),
3496
3752
  [config.serverUrl, config.apiKey]
@@ -3512,7 +3768,7 @@ var WireOnboarding = ({
3512
3768
  });
3513
3769
  }, [session, sessionId, boundUserId, reportTarget]);
3514
3770
  const cards = components != null ? components : onboardingComponents;
3515
- if (!session) {
3771
+ if (!session || autoJoinPending) {
3516
3772
  return /* @__PURE__ */ jsx(OnboardingThemeProvider, { theme, children: /* @__PURE__ */ jsx(
3517
3773
  LoadingScreen,
3518
3774
  {
@@ -3978,16 +4234,37 @@ var useResolvedFeatures = (options) => {
3978
4234
  };
3979
4235
 
3980
4236
  // src/config/wireConfigFromEnv.ts
4237
+ var WIRE_ENV_VARS = [
4238
+ "EXPO_PUBLIC_WIREAI_API_KEY",
4239
+ "EXPO_PUBLIC_WIREAI_SERVER_URL",
4240
+ "EXPO_PUBLIC_WIREAI_APP_ID"
4241
+ ];
4242
+ var warnInDev3 = (message) => {
4243
+ if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
4244
+ console.warn(message);
4245
+ }
4246
+ };
3981
4247
  var wireConfigFromEnv = (overrides) => {
3982
- var _a2, _b, _c, _d;
4248
+ var _a2, _b, _c, _d, _e;
3983
4249
  const apiKey = (_a2 = overrides == null ? void 0 : overrides.apiKey) != null ? _a2 : process.env.EXPO_PUBLIC_WIREAI_API_KEY;
3984
4250
  const serverUrl = (_b = overrides == null ? void 0 : overrides.serverUrl) != null ? _b : process.env.EXPO_PUBLIC_WIREAI_SERVER_URL;
3985
4251
  const appId = (_d = (_c = overrides == null ? void 0 : overrides.appId) != null ? _c : process.env.EXPO_PUBLIC_WIREAI_APP_ID) != null ? _d : "default";
3986
- if (!apiKey || !serverUrl) return null;
4252
+ if (!apiKey || !serverUrl) {
4253
+ const missing = [
4254
+ apiKey ? void 0 : "EXPO_PUBLIC_WIREAI_API_KEY",
4255
+ serverUrl ? void 0 : "EXPO_PUBLIC_WIREAI_SERVER_URL"
4256
+ ].filter(Boolean);
4257
+ warnInDev3(
4258
+ `[wireai] wireConfigFromEnv() returned null: ${missing.join(" and ")} ${missing.length > 1 ? "are" : "is"} missing. The kit is now FULLY DISABLED (no onboarding, no analytics, no gates) and nothing else will report an error. Set the var(s) in your env / EAS secrets.`
4259
+ );
4260
+ return null;
4261
+ }
4262
+ const appVersion = (_e = overrides == null ? void 0 : overrides.appVersion) != null ? _e : detectAppVersion();
3987
4263
  return {
3988
4264
  apiKey,
3989
4265
  serverUrl,
3990
4266
  appId,
4267
+ ...appVersion ? { appVersion } : {},
3991
4268
  ...(overrides == null ? void 0 : overrides.metadata) ? { metadata: overrides.metadata } : {}
3992
4269
  };
3993
4270
  };
@@ -4048,104 +4325,6 @@ var attributionMetadata = (a) => {
4048
4325
  return { attribution };
4049
4326
  };
4050
4327
 
4051
- // src/context/userContext.ts
4052
- var RESERVED_USER_CONTEXT_KEYS = [
4053
- "device_key",
4054
- "app_version",
4055
- "app_build",
4056
- "network_type",
4057
- "session_count",
4058
- "returning",
4059
- "platform",
4060
- "user_email",
4061
- "user_email_hashed"
4062
- ];
4063
- var EXTRA_KEY_PREFIX = "custom.";
4064
- var isWireScalar = (value) => {
4065
- const t = typeof value;
4066
- if (t === "string" || t === "boolean") return true;
4067
- if (t === "number") return Number.isFinite(value);
4068
- return false;
4069
- };
4070
- var hashEmailFnv1a = (email) => {
4071
- const normalized = email.trim().toLowerCase();
4072
- let hash = 2166136261;
4073
- for (let i = 0; i < normalized.length; i++) {
4074
- hash ^= normalized.charCodeAt(i);
4075
- hash = Math.imul(hash, 16777619);
4076
- }
4077
- return (hash >>> 0).toString(16).padStart(8, "0");
4078
- };
4079
- var cleanString = (value) => {
4080
- if (typeof value !== "string") return void 0;
4081
- const trimmed = value.trim();
4082
- return trimmed.length > 0 ? trimmed : void 0;
4083
- };
4084
- var namespaceExtra = (extra) => {
4085
- const out = {};
4086
- if (!extra || typeof extra !== "object") return out;
4087
- for (const [key, value] of Object.entries(extra)) {
4088
- const cleanKey = cleanString(key);
4089
- if (!cleanKey) continue;
4090
- if (!isWireScalar(value)) continue;
4091
- out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
4092
- }
4093
- return out;
4094
- };
4095
- var analyticsUserIdStorageKey = (appId) => `wireai:analytics:userId:${appId != null ? appId : "default"}`;
4096
- var clearPiiFromContext = (ctx = {}) => {
4097
- const rest = {};
4098
- if (typeof ctx.appVersion === "string") rest.appVersion = ctx.appVersion;
4099
- if (typeof ctx.deviceKey === "string") rest.deviceKey = ctx.deviceKey;
4100
- return rest;
4101
- };
4102
- var clearUserContext = async (opts = {}) => {
4103
- const storage = opts.storage;
4104
- if (!storage) return;
4105
- try {
4106
- await storage.removeItem(analyticsUserIdStorageKey(opts.appId));
4107
- } catch {
4108
- }
4109
- };
4110
- var resolveUserContext = (ctx = {}, opts = {}) => {
4111
- var _a2;
4112
- const result = {};
4113
- const bucket = {};
4114
- const userId = sanitizeUserId(ctx.userId);
4115
- if (userId) result.userId = userId;
4116
- const deviceKey = cleanString(ctx.deviceKey);
4117
- if (deviceKey) {
4118
- result.deviceKey = deviceKey;
4119
- bucket.device_key = deviceKey;
4120
- }
4121
- const appVersion = (_a2 = cleanString(ctx.appVersion)) != null ? _a2 : cleanString(opts.autoAppVersion);
4122
- if (appVersion) {
4123
- result.appVersion = appVersion;
4124
- bucket.app_version = appVersion;
4125
- }
4126
- const email = cleanString(ctx.userEmail);
4127
- if (email) {
4128
- if (ctx.hashEmail) {
4129
- bucket.user_email = hashEmailFnv1a(email);
4130
- bucket.user_email_hashed = true;
4131
- } else {
4132
- bucket.user_email = email;
4133
- }
4134
- }
4135
- Object.assign(bucket, namespaceExtra(ctx.extra));
4136
- if (Object.keys(bucket).length > 0) result.userContext = bucket;
4137
- return result;
4138
- };
4139
-
4140
- // src/context/deviceId.ts
4141
- var AUTO_DEVICE_ID_PREFIX = "wdev_";
4142
- var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
4143
- var randomChunk = () => Math.floor(Math.random() * 4294967296).toString(36).padStart(6, "0");
4144
- var mintDeviceId = () => {
4145
- const time = Date.now().toString(36);
4146
- return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
4147
- };
4148
-
4149
4328
  // src/activation/revalidation.ts
4150
4329
  var REVALIDATION_SLOT = /* @__PURE__ */ Symbol.for(
4151
4330
  "@wireai/activation:activationRevalidation"
@@ -4192,32 +4371,31 @@ var createWireActivation = (config) => {
4192
4371
  var _a2, _b;
4193
4372
  const target = { serverUrl: config.serverUrl, apiKey: config.apiKey };
4194
4373
  const explicitDeviceKey = (_b = clean(config.deviceKey)) != null ? _b : clean((_a2 = config.userContext) == null ? void 0 : _a2.deviceKey);
4195
- let autoDeviceKey = explicitDeviceKey != null ? explicitDeviceKey : mintDeviceId();
4196
- if (config.storage && !explicitDeviceKey) {
4197
- const storage = config.storage;
4198
- const key = deviceIdStorageKey(config.appId);
4199
- void storage.getItem(key).then((saved) => {
4200
- const persisted = clean(saved != null ? saved : void 0);
4201
- if (persisted) autoDeviceKey = persisted;
4202
- else void storage.setItem(key, autoDeviceKey).catch(() => {
4203
- });
4204
- }).catch(() => {
4205
- });
4206
- }
4374
+ const autoDeviceKeyOptions = {
4375
+ appId: config.appId,
4376
+ // An explicit key opts out of minting AND persisting (unchanged contract).
4377
+ storage: explicitDeviceKey ? void 0 : config.storage
4378
+ };
4379
+ if (!explicitDeviceKey) resolveAutoDeviceKey(autoDeviceKeyOptions);
4380
+ const detectedAppVersion = detectAppVersion();
4207
4381
  const applyContext = (event) => {
4208
- var _a3, _b2;
4382
+ var _a3, _b2, _c;
4209
4383
  const resolved = resolveUserContext(
4210
- { ...(_a3 = config.userContext) != null ? _a3 : {}, deviceKey: explicitDeviceKey != null ? explicitDeviceKey : autoDeviceKey },
4211
- { autoAppVersion: config.appVersion }
4384
+ // `??` is lazy on purpose: an explicit key must never even touch the auto registry.
4385
+ {
4386
+ ...(_a3 = config.userContext) != null ? _a3 : {},
4387
+ deviceKey: explicitDeviceKey != null ? explicitDeviceKey : resolveAutoDeviceKey(autoDeviceKeyOptions)
4388
+ },
4389
+ { autoAppVersion: (_b2 = config.appVersion) != null ? _b2 : detectedAppVersion }
4212
4390
  );
4213
4391
  if (resolved.userContext) {
4214
- event.user_context = { ...resolved.userContext, ...(_b2 = event.user_context) != null ? _b2 : {} };
4392
+ event.user_context = { ...resolved.userContext, ...(_c = event.user_context) != null ? _c : {} };
4215
4393
  }
4216
4394
  if (resolved.userId && !event.user_id) event.user_id = resolved.userId;
4217
4395
  };
4218
4396
  const track = async (name2, meta) => {
4219
- const sessionId = getCurrentSessionId();
4220
- if (!clean(name2) || !sessionId) return false;
4397
+ if (!clean(name2)) return false;
4398
+ const sessionId = ensureCurrentSessionId();
4221
4399
  const event = {
4222
4400
  event_type: "app_event",
4223
4401
  session_id: sessionId,
@@ -4244,9 +4422,16 @@ var useActivationRevalidation = () => useSyncExternalStore(
4244
4422
  getActivationRevalidationVersion
4245
4423
  );
4246
4424
  var useWireActivation = (config) => {
4425
+ var _a2;
4247
4426
  const ref = useRef(void 0);
4248
4427
  const prevKeys = useRef("");
4249
- const currentKeys = `${config.serverUrl}|${config.apiKey}|${config.appId}|${config.deviceKey}`;
4428
+ const currentKeys = [
4429
+ config.serverUrl,
4430
+ config.apiKey,
4431
+ config.appId,
4432
+ config.deviceKey,
4433
+ (_a2 = config.userContext) == null ? void 0 : _a2.deviceKey
4434
+ ].join("|");
4250
4435
  if (!ref.current || prevKeys.current !== currentKeys) {
4251
4436
  prevKeys.current = currentKeys;
4252
4437
  ref.current = createWireActivation(config);
@@ -4255,6 +4440,154 @@ var useWireActivation = (config) => {
4255
4440
  return { track: ref.current.track, sessionId: ref.current.sessionId, revalidation };
4256
4441
  };
4257
4442
 
4443
+ // src/revenuecat/purchaseEvents.ts
4444
+ var WIRE_PURCHASE_EVENTS = {
4445
+ /** The paywall became visible (offerings loaded). */
4446
+ paywallShown: "wire_paywall_shown",
4447
+ /** The user tapped buy; the store sheet is about to open. */
4448
+ checkoutStarted: "wire_checkout_started",
4449
+ /** The store confirmed the purchase AND the entitlement is now active. */
4450
+ purchased: "wire_purchase_completed",
4451
+ /** The purchase did not land: a user cancel or a real store/network error (see `reason`). */
4452
+ purchaseFailed: "wire_purchase_failed",
4453
+ /** A restore ran (whether or not it produced an entitlement; see `plan_tier`). */
4454
+ restored: "wire_purchase_restored"
4455
+ };
4456
+ var PLAN_TIER_CONTEXT_KEY = "plan_tier";
4457
+ var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
4458
+ var activeEntitlement = (info, entitlementId) => {
4459
+ var _a2, _b;
4460
+ const active = asRecord((_b = asRecord((_a2 = asRecord(info)) == null ? void 0 : _a2.entitlements)) == null ? void 0 : _b.active);
4461
+ const found = active == null ? void 0 : active[entitlementId];
4462
+ const entitlement = asRecord(found);
4463
+ if (!entitlement) return void 0;
4464
+ return entitlement.isActive === false ? void 0 : entitlement;
4465
+ };
4466
+ var isTrial = (entitlement) => typeof entitlement.periodType === "string" && entitlement.periodType.toUpperCase() === "TRIAL";
4467
+ var resolvePlanTier = (info, entitlementId) => {
4468
+ const entitlement = activeEntitlement(info, entitlementId);
4469
+ if (!entitlement) return "free";
4470
+ return isTrial(entitlement) ? "trial" : "paid";
4471
+ };
4472
+ var describePackage = (pkg) => {
4473
+ const props = {};
4474
+ if (!pkg) return props;
4475
+ if (typeof pkg.identifier === "string") props.package_id = pkg.identifier;
4476
+ if (typeof pkg.packageType === "string") props.package_type = pkg.packageType;
4477
+ if (typeof pkg.offeringIdentifier === "string") props.offering_id = pkg.offeringIdentifier;
4478
+ const product = asRecord(pkg.product);
4479
+ if (product) {
4480
+ if (typeof product.identifier === "string") props.product_id = product.identifier;
4481
+ if (typeof product.price === "number" && Number.isFinite(product.price)) {
4482
+ props.price = product.price;
4483
+ }
4484
+ if (typeof product.currencyCode === "string") props.currency = product.currencyCode;
4485
+ }
4486
+ return props;
4487
+ };
4488
+ var describeEntitlement = (info, entitlementId) => {
4489
+ const entitlement = activeEntitlement(info, entitlementId);
4490
+ const props = {
4491
+ entitlement: entitlementId,
4492
+ plan_tier: entitlement ? isTrial(entitlement) ? "trial" : "paid" : "free"
4493
+ };
4494
+ if (!entitlement) return props;
4495
+ if (typeof entitlement.periodType === "string") props.period_type = entitlement.periodType;
4496
+ props.is_trial = isTrial(entitlement);
4497
+ if (typeof entitlement.willRenew === "boolean") props.will_renew = entitlement.willRenew;
4498
+ if (typeof entitlement.store === "string") props.store = entitlement.store;
4499
+ if (typeof entitlement.productIdentifier === "string") {
4500
+ props.product_id = entitlement.productIdentifier;
4501
+ }
4502
+ if (typeof entitlement.isSandbox === "boolean") props.is_sandbox = entitlement.isSandbox;
4503
+ return props;
4504
+ };
4505
+ var PURCHASE_CANCELLED_CODE = "1";
4506
+ var isUserCancelled = (error) => {
4507
+ const record = asRecord(error);
4508
+ if (!record) return false;
4509
+ if (record.userCancelled === true) return true;
4510
+ return record.code === PURCHASE_CANCELLED_CODE;
4511
+ };
4512
+ var describeFailure = (error) => {
4513
+ const record = asRecord(error);
4514
+ const code = typeof (record == null ? void 0 : record.code) === "string" ? record.code : "unknown";
4515
+ return { reason: isUserCancelled(error) ? "cancelled" : "error", code };
4516
+ };
4517
+
4518
+ // src/revenuecat/revenueCatBridge.ts
4519
+ var createRevenueCatBridge = (config) => {
4520
+ const { analytics, entitlementId } = config;
4521
+ const writeTier = config.writePlanTier !== false;
4522
+ const emit = (event, props) => {
4523
+ try {
4524
+ const result = analytics.track(event, { ...config.commonProps, ...props });
4525
+ if (result && typeof result.catch === "function") {
4526
+ void result.catch(() => {
4527
+ });
4528
+ }
4529
+ } catch {
4530
+ }
4531
+ };
4532
+ const syncPlanTier = (customerInfo) => {
4533
+ var _a2;
4534
+ const tier = resolvePlanTier(customerInfo, entitlementId);
4535
+ if (!writeTier) return tier;
4536
+ try {
4537
+ (_a2 = analytics.setUserContext) == null ? void 0 : _a2.call(analytics, { extra: { [PLAN_TIER_CONTEXT_KEY]: tier } });
4538
+ } catch {
4539
+ }
4540
+ return tier;
4541
+ };
4542
+ const paywallShown = (offering, props) => {
4543
+ var _a2, _b;
4544
+ const shown = {
4545
+ packages_count: (_b = (_a2 = offering == null ? void 0 : offering.availablePackages) == null ? void 0 : _a2.length) != null ? _b : 0
4546
+ };
4547
+ if (typeof (offering == null ? void 0 : offering.identifier) === "string") shown.offering_id = offering.identifier;
4548
+ emit(WIRE_PURCHASE_EVENTS.paywallShown, { ...shown, ...props });
4549
+ };
4550
+ const checkoutStarted = (pkg, props) => {
4551
+ emit(WIRE_PURCHASE_EVENTS.checkoutStarted, { ...describePackage(pkg), ...props });
4552
+ };
4553
+ const purchaseCompleted = (customerInfo, pkg, props) => {
4554
+ const tier = syncPlanTier(customerInfo);
4555
+ const entitled = tier !== "free";
4556
+ if (entitled) {
4557
+ emit(WIRE_PURCHASE_EVENTS.purchased, {
4558
+ ...describePackage(pkg),
4559
+ ...describeEntitlement(customerInfo, entitlementId),
4560
+ ...props
4561
+ });
4562
+ return true;
4563
+ }
4564
+ emit(WIRE_PURCHASE_EVENTS.purchaseFailed, {
4565
+ ...describePackage(pkg),
4566
+ reason: "not_entitled",
4567
+ code: "unknown",
4568
+ entitlement: entitlementId,
4569
+ ...props
4570
+ });
4571
+ return false;
4572
+ };
4573
+ const purchaseFailed = (error, pkg, props) => {
4574
+ emit(WIRE_PURCHASE_EVENTS.purchaseFailed, {
4575
+ ...describePackage(pkg),
4576
+ ...describeFailure(error),
4577
+ ...props
4578
+ });
4579
+ };
4580
+ const purchasesRestored = (customerInfo, props) => {
4581
+ const tier = syncPlanTier(customerInfo);
4582
+ emit(WIRE_PURCHASE_EVENTS.restored, {
4583
+ ...describeEntitlement(customerInfo, entitlementId),
4584
+ ...props
4585
+ });
4586
+ return tier !== "free";
4587
+ };
4588
+ return { paywallShown, checkoutStarted, purchaseCompleted, purchaseFailed, purchasesRestored, syncPlanTier };
4589
+ };
4590
+
4258
4591
  // src/session-analytics/reportSessionStart.ts
4259
4592
  var SESSION_STARTED_EVENT = "app.session_started";
4260
4593
  var _emitted = /* @__PURE__ */ new Set();
@@ -4307,6 +4640,8 @@ var reportSessionStart = (opts) => {
4307
4640
  method: "POST",
4308
4641
  headers,
4309
4642
  body: JSON.stringify({ events: [event] })
4643
+ }).then((res) => {
4644
+ warnOnSkippedEvents(res);
4310
4645
  }).catch(() => {
4311
4646
  });
4312
4647
  } catch {
@@ -4317,6 +4652,12 @@ var useSessionStart = (config, options = {}) => {
4317
4652
  const latest = useRef({ config, options });
4318
4653
  latest.current = { config, options };
4319
4654
  useEffect(() => {
4655
+ const resolveDeviceKey = (cfg, opts) => {
4656
+ const host = typeof opts.deviceKey === "string" && opts.deviceKey.trim() ? opts.deviceKey : void 0;
4657
+ if (host) return host;
4658
+ if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
4659
+ return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
4660
+ };
4320
4661
  const fire = () => {
4321
4662
  var _a2, _b;
4322
4663
  const { config: cfg, options: opts } = latest.current;
@@ -4329,7 +4670,7 @@ var useSessionStart = (config, options = {}) => {
4329
4670
  target,
4330
4671
  // A fresh per-open id each fire; the emitter's once-guard dedupes within the open.
4331
4672
  userId: opts.userId,
4332
- deviceKey: opts.deviceKey,
4673
+ deviceKey: resolveDeviceKey(cfg, opts),
4333
4674
  sessionCount: opts.sessionCount,
4334
4675
  appVersion: (_b = cfg.appVersion) != null ? _b : device.appVersion,
4335
4676
  platform: Platform.OS,
@@ -4437,11 +4778,13 @@ var reportFirstOpen = (opts) => {
4437
4778
  })();
4438
4779
  };
4439
4780
  var wireLifecycleEvents = (opts) => {
4440
- reportFirstOpen(opts);
4781
+ var _a2;
4782
+ const sessionId = (_a2 = opts.sessionId) != null ? _a2 : makeSessionId();
4783
+ reportFirstOpen({ ...opts, sessionId });
4441
4784
  reportSessionStart({
4442
4785
  target: opts.target,
4443
4786
  sink: opts.sink,
4444
- sessionId: opts.sessionId,
4787
+ sessionId,
4445
4788
  userId: opts.userId,
4446
4789
  deviceKey: opts.deviceKey,
4447
4790
  sessionCount: opts.sessionCount,
@@ -4576,6 +4919,7 @@ var createEventQueue = (options) => {
4576
4919
  const timer = setTimeout(() => controller == null ? void 0 : controller.abort(), 15e3);
4577
4920
  try {
4578
4921
  const res = await fetch(req.url, { ...req.init, signal: controller == null ? void 0 : controller.signal });
4922
+ warnOnSkippedEvents(res);
4579
4923
  return !!(res && res.ok);
4580
4924
  } catch {
4581
4925
  return false;
@@ -4660,15 +5004,14 @@ var useLifecycleEvents = (config, options = {}) => {
4660
5004
  latest.current = { config, options };
4661
5005
  const queueRef = useRef(void 0);
4662
5006
  useEffect(() => {
4663
- var _a2;
4664
5007
  const resolveSink = () => {
4665
- var _a3, _b;
5008
+ var _a2, _b;
4666
5009
  const { config: cfg, options: opts } = latest.current;
4667
5010
  if (opts.sink) return opts.sink;
4668
5011
  if (!(cfg == null ? void 0 : cfg.serverUrl)) return void 0;
4669
5012
  if (!queueRef.current) {
4670
5013
  queueRef.current = createEventQueue({
4671
- target: { serverUrl: cfg.serverUrl, apiKey: (_a3 = cfg.apiKey) != null ? _a3 : "" },
5014
+ target: { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" },
4672
5015
  storage: cfg.storage,
4673
5016
  // Dedicated key so the hook's internal queue never collides with a host's main queue.
4674
5017
  storageKey: `wireai:evtq:lifecycle:${(_b = cfg.appId) != null ? _b : "default"}`,
@@ -4678,12 +5021,18 @@ var useLifecycleEvents = (config, options = {}) => {
4678
5021
  return queueRef.current.enqueue;
4679
5022
  };
4680
5023
  const targetOf = (cfg) => {
4681
- var _a3;
4682
- return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a3 = cfg.apiKey) != null ? _a3 : "" } : void 0;
5024
+ var _a2;
5025
+ return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" } : void 0;
5026
+ };
5027
+ const resolveDeviceKey = (cfg, opts) => {
5028
+ const host = typeof opts.deviceKey === "string" && opts.deviceKey.trim() ? opts.deviceKey : void 0;
5029
+ if (host) return host;
5030
+ if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
5031
+ return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
4683
5032
  };
4684
5033
  const mountOpenSessionId = makeSessionId();
4685
5034
  const fireSession = (sessionId) => {
4686
- var _a3;
5035
+ var _a2;
4687
5036
  const { config: cfg, options: opts } = latest.current;
4688
5037
  if (opts.enabled === false) return;
4689
5038
  if (!(cfg == null ? void 0 : cfg.serverUrl) && !opts.sink) return;
@@ -4694,35 +5043,45 @@ var useLifecycleEvents = (config, options = {}) => {
4694
5043
  sink: resolveSink(),
4695
5044
  sessionId,
4696
5045
  userId: opts.userId,
4697
- deviceKey: opts.deviceKey,
5046
+ deviceKey: resolveDeviceKey(cfg, opts),
4698
5047
  sessionCount: opts.sessionCount,
4699
- appVersion: (_a3 = cfg == null ? void 0 : cfg.appVersion) != null ? _a3 : device.appVersion,
5048
+ appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
4700
5049
  platform: Platform.OS,
4701
5050
  device,
4702
5051
  meta: opts.meta
4703
5052
  });
4704
5053
  };
4705
- fireSession(mountOpenSessionId);
4706
- {
5054
+ const fireMountOpen = () => {
5055
+ var _a2;
5056
+ fireSession(mountOpenSessionId);
4707
5057
  const { config: cfg, options: opts } = latest.current;
4708
- if (opts.enabled !== false) {
4709
- const device = collectDeviceContext();
4710
- if (cfg == null ? void 0 : cfg.appVersion) device.appVersion = cfg.appVersion;
4711
- reportFirstOpen({
4712
- target: targetOf(cfg),
4713
- sink: resolveSink(),
4714
- sessionId: mountOpenSessionId,
4715
- storage: cfg == null ? void 0 : cfg.storage,
4716
- appId: cfg == null ? void 0 : cfg.appId,
4717
- userId: opts.userId,
4718
- deviceKey: opts.deviceKey,
4719
- sessionCount: opts.sessionCount,
4720
- appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
4721
- platform: Platform.OS,
4722
- device,
4723
- meta: opts.meta
4724
- });
4725
- }
5058
+ if (opts.enabled === false) return;
5059
+ const device = collectDeviceContext();
5060
+ if (cfg == null ? void 0 : cfg.appVersion) device.appVersion = cfg.appVersion;
5061
+ reportFirstOpen({
5062
+ target: targetOf(cfg),
5063
+ sink: resolveSink(),
5064
+ sessionId: mountOpenSessionId,
5065
+ storage: cfg == null ? void 0 : cfg.storage,
5066
+ appId: cfg == null ? void 0 : cfg.appId,
5067
+ userId: opts.userId,
5068
+ deviceKey: resolveDeviceKey(cfg, opts),
5069
+ sessionCount: opts.sessionCount,
5070
+ appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
5071
+ platform: Platform.OS,
5072
+ device,
5073
+ meta: opts.meta
5074
+ });
5075
+ };
5076
+ let cancelled = false;
5077
+ const { config: mountCfg, options: mountOpts } = latest.current;
5078
+ const hostKey = typeof mountOpts.deviceKey === "string" && mountOpts.deviceKey.trim() ? mountOpts.deviceKey : void 0;
5079
+ if (!hostKey && (mountCfg == null ? void 0 : mountCfg.storage)) {
5080
+ void hydrateAutoDeviceKey({ appId: mountCfg.appId, storage: mountCfg.storage }).then(() => {
5081
+ if (!cancelled) fireMountOpen();
5082
+ });
5083
+ } else {
5084
+ fireMountOpen();
4726
5085
  }
4727
5086
  let backgroundedAt = null;
4728
5087
  const onChange = (state) => {
@@ -4738,11 +5097,12 @@ var useLifecycleEvents = (config, options = {}) => {
4738
5097
  };
4739
5098
  const sub = AppState.addEventListener("change", onChange);
4740
5099
  return () => {
5100
+ cancelled = true;
4741
5101
  if (sub && typeof sub.remove === "function") sub.remove();
4742
5102
  };
4743
5103
  }, []);
4744
5104
  };
4745
5105
 
4746
- export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_SESSION_TTL_MS, DemoOnboarding, DoneBlock, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, RESERVED_USER_CONTEXT_KEYS, SESSION_STARTED_EVENT, SelectionCard, StatusCard, StepProgress, TextInputCard, USER_ID_MAX_LENGTH, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_ONBOARDING_EVENTS, WireFeaturesProvider, WireIcon, WireOnboarding, analyticsUserIdStorageKey, attributionMetadata, bumpActivationRevalidation, clearPersistedSession, clearPiiFromContext, clearUserContext, collectDeviceContext, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, detectAppVersion, detectNativeModel, deviceIdStorageKey, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, getCurrentSessionId, hashEmailFnv1a, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, isWireScalar, loadPersistedSession, looksLikeEmail, lookupIconGlyph, makeSessionId, mergeTheme, mintDeviceId, motionSpec_exports as motionSpec, namespaceExtra, onboardingComponents, parseWireFeatures, peekPersistedSession, readCachedFeatures, readProgress, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetCurrentSessionId, resetFirstOpenLatch, resetSessionStartGuard, resolveUserContext, sanitizeUserId, savePersistedSession, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
5106
+ export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_SESSION_TTL_MS, DemoOnboarding, DoneBlock, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, PLAN_TIER_CONTEXT_KEY, RESERVED_USER_CONTEXT_KEYS, SESSION_STARTED_EVENT, SelectionCard, StatusCard, StepProgress, TextInputCard, USER_ID_MAX_LENGTH, WIRE_ENV_VARS, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_ONBOARDING_EVENTS, WIRE_PURCHASE_EVENTS, WireFeaturesProvider, WireIcon, WireOnboarding, activationJoinContext, activeEntitlement, analyticsUserIdStorageKey, attributionMetadata, bumpActivationRevalidation, clearPersistedSession, clearPiiFromContext, clearUserContext, collectDeviceContext, createRevenueCatBridge, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, describeEntitlement, describeFailure, describePackage, detectAppVersion, detectNativeModel, deviceIdStorageKey, ensureCurrentSessionId, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, getCurrentSessionId, hashEmailFnv1a, hydrateAutoDeviceKey, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, isUserCancelled, isWireScalar, loadPersistedSession, looksLikeEmail, lookupIconGlyph, makeSessionId, mergeTheme, mintDeviceId, motionSpec_exports as motionSpec, namespaceExtra, onboardingComponents, parseWireFeatures, peekPersistedSession, readCachedFeatures, readProgress, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetAutoDeviceKeys, resetCurrentSessionId, resetFirstOpenLatch, resetSessionStartGuard, resolveAutoDeviceKey, resolvePlanTier, resolveUserContext, sanitizeUserId, savePersistedSession, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
4747
5107
  //# sourceMappingURL=index.mjs.map
4748
5108
  //# sourceMappingURL=index.mjs.map