@wireai/activation 0.4.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
1
  import { useRef, useEffect } from 'react';
2
2
  import { Platform, Dimensions, I18nManager } from 'react-native';
3
3
 
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
10
+
4
11
  // src/reviews/transport.ts
5
12
  var reportAppEvent = (target, name, options = {}) => {
6
13
  if (!(target == null ? void 0 : target.serverUrl) || !name) return;
@@ -155,6 +162,57 @@ var toAnalyticsEvent = (event) => {
155
162
  }
156
163
  }
157
164
  };
165
+
166
+ // src/device/appVersion.ts
167
+ var coerceVersion = (value) => {
168
+ if (typeof value !== "string") return void 0;
169
+ const trimmed = value.trim();
170
+ return trimmed.length > 0 ? trimmed : void 0;
171
+ };
172
+ var runtimeRequire = (moduleName) => {
173
+ try {
174
+ if (typeof __require !== "function") return void 0;
175
+ return __require(moduleName);
176
+ } catch {
177
+ return void 0;
178
+ }
179
+ };
180
+ var interop = (mod) => {
181
+ if (!mod || typeof mod !== "object") return void 0;
182
+ const def = mod.default;
183
+ if (def && typeof def === "object") return def;
184
+ return mod;
185
+ };
186
+ var safeInterop = (requireModule, moduleName) => {
187
+ try {
188
+ return interop(requireModule(moduleName));
189
+ } catch {
190
+ return void 0;
191
+ }
192
+ };
193
+ var detectAppVersion = (requireModule = runtimeRequire) => {
194
+ try {
195
+ const constants = safeInterop(requireModule, "expo-constants");
196
+ if (constants) {
197
+ const expoConfig = constants.expoConfig;
198
+ if (expoConfig && typeof expoConfig === "object") {
199
+ const fromExpoConfig = coerceVersion(expoConfig.version);
200
+ if (fromExpoConfig) return fromExpoConfig;
201
+ }
202
+ const fromNative = coerceVersion(constants.nativeAppVersion);
203
+ if (fromNative) return fromNative;
204
+ }
205
+ const application = safeInterop(requireModule, "expo-application");
206
+ if (application) {
207
+ const fromApplication = coerceVersion(application.nativeApplicationVersion);
208
+ if (fromApplication) return fromApplication;
209
+ }
210
+ } catch {
211
+ }
212
+ return void 0;
213
+ };
214
+
215
+ // src/device/deviceContext.ts
158
216
  var deriveFormFactor = (iosIdiom, width, height) => {
159
217
  if (iosIdiom === "pad") return "tablet";
160
218
  if (iosIdiom === "phone") return "phone";
@@ -224,16 +282,20 @@ var collectDeviceContext = () => {
224
282
  if (resolved.timeZone) ctx.timeZone = resolved.timeZone;
225
283
  } catch {
226
284
  }
285
+ const appVersion = detectAppVersion();
286
+ if (appVersion) ctx.appVersion = appVersion;
227
287
  return ctx;
228
288
  };
229
289
 
230
290
  // src/analytics/contextEnvelope.ts
231
291
  var buildContextEnvelope = (input = {}) => {
292
+ var _a;
232
293
  const device = { ...collectDeviceContext() };
233
- if (input.appVersion && !device.appVersion) device.appVersion = input.appVersion;
294
+ if (input.appVersion) device.appVersion = input.appVersion;
295
+ const effectiveAppVersion = (_a = input.appVersion) != null ? _a : device.appVersion;
234
296
  const envelope = { device };
235
297
  if (input.sessionId) envelope.sessionId = input.sessionId;
236
- if (input.appVersion) envelope.appVersion = input.appVersion;
298
+ if (effectiveAppVersion) envelope.appVersion = effectiveAppVersion;
237
299
  if (input.appBuild) envelope.appBuild = input.appBuild;
238
300
  if (input.networkType) envelope.networkType = input.networkType;
239
301
  return envelope;
@@ -447,6 +509,16 @@ var createEventQueue = (options) => {
447
509
  return { enqueue, flush, notifyOnline, size };
448
510
  };
449
511
 
512
+ // src/analytics/currentSession.ts
513
+ var _currentSessionId;
514
+ var setCurrentSessionId = (id) => {
515
+ if (typeof id === "string" && id.length > 0) _currentSessionId = id;
516
+ };
517
+ var getCurrentSessionId = () => _currentSessionId;
518
+ var resetCurrentSessionId = () => {
519
+ _currentSessionId = void 0;
520
+ };
521
+
450
522
  // src/identity/userIdentity.ts
451
523
  var USER_ID_MAX_LENGTH = 128;
452
524
  var sanitizeUserId = (raw) => {
@@ -456,12 +528,79 @@ var sanitizeUserId = (raw) => {
456
528
  return trimmed.length > USER_ID_MAX_LENGTH ? trimmed.slice(0, USER_ID_MAX_LENGTH) : trimmed;
457
529
  };
458
530
 
531
+ // src/context/userContext.ts
532
+ var EXTRA_KEY_PREFIX = "custom.";
533
+ var isWireScalar = (value) => {
534
+ const t = typeof value;
535
+ if (t === "string" || t === "boolean") return true;
536
+ if (t === "number") return Number.isFinite(value);
537
+ return false;
538
+ };
539
+ var hashEmailFnv1a = (email) => {
540
+ const normalized = email.trim().toLowerCase();
541
+ let hash = 2166136261;
542
+ for (let i = 0; i < normalized.length; i++) {
543
+ hash ^= normalized.charCodeAt(i);
544
+ hash = Math.imul(hash, 16777619);
545
+ }
546
+ return (hash >>> 0).toString(16).padStart(8, "0");
547
+ };
548
+ var cleanString = (value) => {
549
+ if (typeof value !== "string") return void 0;
550
+ const trimmed = value.trim();
551
+ return trimmed.length > 0 ? trimmed : void 0;
552
+ };
553
+ var namespaceExtra = (extra) => {
554
+ const out = {};
555
+ if (!extra || typeof extra !== "object") return out;
556
+ for (const [key, value] of Object.entries(extra)) {
557
+ const cleanKey = cleanString(key);
558
+ if (!cleanKey) continue;
559
+ if (!isWireScalar(value)) continue;
560
+ out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
561
+ }
562
+ return out;
563
+ };
564
+ var resolveUserContext = (ctx = {}, opts = {}) => {
565
+ var _a;
566
+ const result = {};
567
+ const bucket = {};
568
+ const userId = sanitizeUserId(ctx.userId);
569
+ if (userId) result.userId = userId;
570
+ const deviceKey = cleanString(ctx.deviceKey);
571
+ if (deviceKey) {
572
+ result.deviceKey = deviceKey;
573
+ bucket.device_key = deviceKey;
574
+ }
575
+ const appVersion = (_a = cleanString(ctx.appVersion)) != null ? _a : cleanString(opts.autoAppVersion);
576
+ if (appVersion) {
577
+ result.appVersion = appVersion;
578
+ bucket.app_version = appVersion;
579
+ }
580
+ const email = cleanString(ctx.userEmail);
581
+ if (email) {
582
+ if (ctx.hashEmail) {
583
+ bucket.user_email = hashEmailFnv1a(email);
584
+ bucket.user_email_hashed = true;
585
+ } else {
586
+ bucket.user_email = email;
587
+ }
588
+ }
589
+ Object.assign(bucket, namespaceExtra(ctx.extra));
590
+ if (Object.keys(bucket).length > 0) result.userContext = bucket;
591
+ return result;
592
+ };
593
+
459
594
  // src/analytics/analyticsFacade.ts
460
595
  var createAnalytics = (config, options = {}) => {
461
- var _a, _b;
462
- const sessionId = (_a = config.sessionId) != null ? _a : makeSessionId();
596
+ var _a, _b, _c, _d;
597
+ const instanceSessionId = (_a = config.sessionId) != null ? _a : makeSessionId();
598
+ const resolveSessionId = () => {
599
+ var _a2, _b2;
600
+ return (_b2 = (_a2 = config.sessionId) != null ? _a2 : getCurrentSessionId()) != null ? _b2 : instanceSessionId;
601
+ };
463
602
  const envelope = () => buildContextEnvelope({
464
- sessionId,
603
+ sessionId: resolveSessionId(),
465
604
  appVersion: config.appVersion,
466
605
  appBuild: config.appBuild,
467
606
  networkType: config.networkType
@@ -473,23 +612,45 @@ var createAnalytics = (config, options = {}) => {
473
612
  envelope,
474
613
  ...options
475
614
  });
476
- let boundUserId;
477
- const storageKey = `wireai:analytics:userId:${(_b = config.appId) != null ? _b : "default"}`;
615
+ let userContext = { ...(_b = config.userContext) != null ? _b : {} };
616
+ let boundUserId = sanitizeUserId((_c = config.userContext) == null ? void 0 : _c.userId);
617
+ const storageKey = `wireai:analytics:userId:${(_d = config.appId) != null ? _d : "default"}`;
478
618
  if (config.storage) {
479
619
  void config.storage.getItem(storageKey).then((saved) => {
480
- if (saved) boundUserId = saved;
620
+ if (saved && !boundUserId) boundUserId = saved;
481
621
  }).catch(() => {
482
622
  });
483
623
  }
624
+ const applyContext = (event) => {
625
+ var _a2;
626
+ const resolved = resolveUserContext(userContext, { autoAppVersion: config.appVersion });
627
+ if (resolved.userContext) {
628
+ event.user_context = { ...resolved.userContext, ...(_a2 = event.user_context) != null ? _a2 : {} };
629
+ }
630
+ if (boundUserId && !event.user_id) event.user_id = boundUserId;
631
+ };
632
+ const setUserContext = (partial) => {
633
+ var _a2, _b2;
634
+ if (!partial || typeof partial !== "object") return;
635
+ const mergedExtra = partial.extra || userContext.extra ? { ...(_a2 = userContext.extra) != null ? _a2 : {}, ...(_b2 = partial.extra) != null ? _b2 : {} } : void 0;
636
+ userContext = { ...userContext, ...partial };
637
+ if (mergedExtra) userContext.extra = mergedExtra;
638
+ const uid = sanitizeUserId(partial.userId);
639
+ if (uid) {
640
+ boundUserId = uid;
641
+ if (config.storage) void config.storage.setItem(storageKey, uid).catch(() => {
642
+ });
643
+ }
644
+ };
484
645
  const track = (event, props) => {
485
646
  if (!event) return;
486
647
  const clientEvent = {
487
648
  event_type: "app_event",
488
- session_id: sessionId,
649
+ session_id: resolveSessionId(),
489
650
  question_key: event
490
651
  };
491
652
  if (props && Object.keys(props).length > 0) clientEvent.meta = JSON.stringify(props);
492
- if (boundUserId) clientEvent.user_id = boundUserId;
653
+ applyContext(clientEvent);
493
654
  queue.enqueue(clientEvent);
494
655
  };
495
656
  const screen = (name, props) => {
@@ -497,11 +658,11 @@ var createAnalytics = (config, options = {}) => {
497
658
  const meta = { screen: name, ...props != null ? props : {} };
498
659
  const clientEvent = {
499
660
  event_type: "app_event",
500
- session_id: sessionId,
661
+ session_id: resolveSessionId(),
501
662
  question_key: "screen",
502
663
  meta: JSON.stringify(meta)
503
664
  };
504
- if (boundUserId) clientEvent.user_id = boundUserId;
665
+ applyContext(clientEvent);
505
666
  queue.enqueue(clientEvent);
506
667
  };
507
668
  const identify = (userId, traits) => {
@@ -514,16 +675,20 @@ var createAnalytics = (config, options = {}) => {
514
675
  }
515
676
  const clientEvent = {
516
677
  event_type: "identify",
517
- session_id: sessionId,
678
+ // Reuse the LIVE per-open session id (see `resolveSessionId`) so the server binds identity to
679
+ // the session it already saw instead of back-filling a phantom `session_started`.
680
+ session_id: resolveSessionId(),
518
681
  user_id: clean
519
682
  };
520
683
  if (traits && Object.keys(traits).length > 0) clientEvent.meta = JSON.stringify(traits);
684
+ applyContext(clientEvent);
521
685
  queue.enqueue(clientEvent);
522
686
  };
523
687
  return {
524
688
  track,
525
689
  screen,
526
690
  identify,
691
+ setUserContext,
527
692
  flush: queue.flush,
528
693
  notifyOnline: queue.notifyOnline,
529
694
  size: queue.size
@@ -540,6 +705,6 @@ var useAnalytics = (config, options = {}) => {
540
705
  return ref.current;
541
706
  };
542
707
 
543
- export { WIRE_ONBOARDING_EVENTS, buildContextEnvelope, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, makeSessionId, reportAppEvent, reportClientEvent, reportClientEvents, screenTrackingHandler, toAnalyticsEvent, useAnalytics, useScreenTracking };
708
+ export { WIRE_ONBOARDING_EVENTS, buildContextEnvelope, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, getCurrentSessionId, makeSessionId, reportAppEvent, reportClientEvent, reportClientEvents, resetCurrentSessionId, screenTrackingHandler, setCurrentSessionId, toAnalyticsEvent, useAnalytics, useScreenTracking };
544
709
  //# sourceMappingURL=index.mjs.map
545
710
  //# sourceMappingURL=index.mjs.map