@wireai/activation 0.4.0 → 0.8.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,98 @@ 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/deviceModel.ts
216
+ var coerceModel = (value) => {
217
+ if (typeof value !== "string") return void 0;
218
+ const trimmed = value.trim();
219
+ return trimmed.length > 0 ? trimmed : void 0;
220
+ };
221
+ var runtimeRequire2 = (moduleName) => {
222
+ try {
223
+ if (typeof __require !== "function") return void 0;
224
+ return __require(moduleName);
225
+ } catch {
226
+ return void 0;
227
+ }
228
+ };
229
+ var interop2 = (mod) => {
230
+ if (!mod || typeof mod !== "object") return void 0;
231
+ const def = mod.default;
232
+ if (def && typeof def === "object") return def;
233
+ return mod;
234
+ };
235
+ var safeInterop2 = (requireModule, moduleName) => {
236
+ try {
237
+ return interop2(requireModule(moduleName));
238
+ } catch {
239
+ return void 0;
240
+ }
241
+ };
242
+ var detectNativeModel = (requireModule = runtimeRequire2) => {
243
+ try {
244
+ const device = safeInterop2(requireModule, "expo-device");
245
+ if (device) {
246
+ const modelName = coerceModel(device.modelName);
247
+ if (modelName) return modelName;
248
+ const modelId = coerceModel(device.modelId);
249
+ if (modelId) return modelId;
250
+ }
251
+ } catch {
252
+ }
253
+ return void 0;
254
+ };
255
+
256
+ // src/device/deviceContext.ts
158
257
  var deriveFormFactor = (iosIdiom, width, height) => {
159
258
  if (iosIdiom === "pad") return "tablet";
160
259
  if (iosIdiom === "phone") return "phone";
@@ -200,6 +299,8 @@ var collectDeviceContext = () => {
200
299
  ctx.interfaceIdiom = idiom;
201
300
  iosIdiom = idiom;
202
301
  }
302
+ const iosModel = detectNativeModel();
303
+ if (iosModel) ctx.model = iosModel;
203
304
  }
204
305
  } catch {
205
306
  }
@@ -224,16 +325,20 @@ var collectDeviceContext = () => {
224
325
  if (resolved.timeZone) ctx.timeZone = resolved.timeZone;
225
326
  } catch {
226
327
  }
328
+ const appVersion = detectAppVersion();
329
+ if (appVersion) ctx.appVersion = appVersion;
227
330
  return ctx;
228
331
  };
229
332
 
230
333
  // src/analytics/contextEnvelope.ts
231
334
  var buildContextEnvelope = (input = {}) => {
335
+ var _a;
232
336
  const device = { ...collectDeviceContext() };
233
- if (input.appVersion && !device.appVersion) device.appVersion = input.appVersion;
337
+ if (input.appVersion) device.appVersion = input.appVersion;
338
+ const effectiveAppVersion = (_a = input.appVersion) != null ? _a : device.appVersion;
234
339
  const envelope = { device };
235
340
  if (input.sessionId) envelope.sessionId = input.sessionId;
236
- if (input.appVersion) envelope.appVersion = input.appVersion;
341
+ if (effectiveAppVersion) envelope.appVersion = effectiveAppVersion;
237
342
  if (input.appBuild) envelope.appBuild = input.appBuild;
238
343
  if (input.networkType) envelope.networkType = input.networkType;
239
344
  return envelope;
@@ -447,6 +552,16 @@ var createEventQueue = (options) => {
447
552
  return { enqueue, flush, notifyOnline, size };
448
553
  };
449
554
 
555
+ // src/analytics/currentSession.ts
556
+ var _currentSessionId;
557
+ var setCurrentSessionId = (id) => {
558
+ if (typeof id === "string" && id.length > 0) _currentSessionId = id;
559
+ };
560
+ var getCurrentSessionId = () => _currentSessionId;
561
+ var resetCurrentSessionId = () => {
562
+ _currentSessionId = void 0;
563
+ };
564
+
450
565
  // src/identity/userIdentity.ts
451
566
  var USER_ID_MAX_LENGTH = 128;
452
567
  var sanitizeUserId = (raw) => {
@@ -456,16 +571,109 @@ var sanitizeUserId = (raw) => {
456
571
  return trimmed.length > USER_ID_MAX_LENGTH ? trimmed.slice(0, USER_ID_MAX_LENGTH) : trimmed;
457
572
  };
458
573
 
574
+ // src/context/userContext.ts
575
+ var EXTRA_KEY_PREFIX = "custom.";
576
+ var isWireScalar = (value) => {
577
+ const t = typeof value;
578
+ if (t === "string" || t === "boolean") return true;
579
+ if (t === "number") return Number.isFinite(value);
580
+ return false;
581
+ };
582
+ var hashEmailFnv1a = (email) => {
583
+ const normalized = email.trim().toLowerCase();
584
+ let hash = 2166136261;
585
+ for (let i = 0; i < normalized.length; i++) {
586
+ hash ^= normalized.charCodeAt(i);
587
+ hash = Math.imul(hash, 16777619);
588
+ }
589
+ return (hash >>> 0).toString(16).padStart(8, "0");
590
+ };
591
+ var cleanString = (value) => {
592
+ if (typeof value !== "string") return void 0;
593
+ const trimmed = value.trim();
594
+ return trimmed.length > 0 ? trimmed : void 0;
595
+ };
596
+ var namespaceExtra = (extra) => {
597
+ const out = {};
598
+ if (!extra || typeof extra !== "object") return out;
599
+ for (const [key, value] of Object.entries(extra)) {
600
+ const cleanKey = cleanString(key);
601
+ if (!cleanKey) continue;
602
+ if (!isWireScalar(value)) continue;
603
+ out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
604
+ }
605
+ return out;
606
+ };
607
+ var resolveUserContext = (ctx = {}, opts = {}) => {
608
+ var _a;
609
+ const result = {};
610
+ const bucket = {};
611
+ const userId = sanitizeUserId(ctx.userId);
612
+ if (userId) result.userId = userId;
613
+ const deviceKey = cleanString(ctx.deviceKey);
614
+ if (deviceKey) {
615
+ result.deviceKey = deviceKey;
616
+ bucket.device_key = deviceKey;
617
+ }
618
+ const appVersion = (_a = cleanString(ctx.appVersion)) != null ? _a : cleanString(opts.autoAppVersion);
619
+ if (appVersion) {
620
+ result.appVersion = appVersion;
621
+ bucket.app_version = appVersion;
622
+ }
623
+ const email = cleanString(ctx.userEmail);
624
+ if (email) {
625
+ if (ctx.hashEmail) {
626
+ bucket.user_email = hashEmailFnv1a(email);
627
+ bucket.user_email_hashed = true;
628
+ } else {
629
+ bucket.user_email = email;
630
+ }
631
+ }
632
+ Object.assign(bucket, namespaceExtra(ctx.extra));
633
+ if (Object.keys(bucket).length > 0) result.userContext = bucket;
634
+ return result;
635
+ };
636
+
637
+ // src/context/deviceId.ts
638
+ var AUTO_DEVICE_ID_PREFIX = "wdev_";
639
+ var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
640
+ var randomChunk = () => Math.floor(Math.random() * 4294967296).toString(36).padStart(6, "0");
641
+ var mintDeviceId = () => {
642
+ const time = Date.now().toString(36);
643
+ return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
644
+ };
645
+
459
646
  // src/analytics/analyticsFacade.ts
460
647
  var createAnalytics = (config, options = {}) => {
461
- var _a, _b;
462
- const sessionId = (_a = config.sessionId) != null ? _a : makeSessionId();
463
- const envelope = () => buildContextEnvelope({
464
- sessionId,
465
- appVersion: config.appVersion,
466
- appBuild: config.appBuild,
467
- networkType: config.networkType
468
- });
648
+ var _a, _b, _c, _d, _e;
649
+ const instanceSessionId = (_a = config.sessionId) != null ? _a : makeSessionId();
650
+ const resolveSessionId = () => {
651
+ var _a2, _b2;
652
+ return (_b2 = (_a2 = config.sessionId) != null ? _a2 : getCurrentSessionId()) != null ? _b2 : instanceSessionId;
653
+ };
654
+ let userContext = { ...(_b = config.userContext) != null ? _b : {} };
655
+ const hostDeviceKeyAtInit = typeof ((_c = config.userContext) == null ? void 0 : _c.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
656
+ let autoDeviceKey = mintDeviceId();
657
+ if (config.storage && !hostDeviceKeyAtInit) {
658
+ const storage = config.storage;
659
+ const deviceKey = deviceIdStorageKey(config.appId);
660
+ void storage.getItem(deviceKey).then((saved) => {
661
+ const persisted = typeof saved === "string" && saved.trim() ? saved.trim() : void 0;
662
+ if (persisted) autoDeviceKey = persisted;
663
+ else void storage.setItem(deviceKey, autoDeviceKey).catch(() => {
664
+ });
665
+ }).catch(() => {
666
+ });
667
+ }
668
+ const envelope = () => {
669
+ var _a2;
670
+ return buildContextEnvelope({
671
+ sessionId: resolveSessionId(),
672
+ appVersion: (_a2 = userContext.appVersion) != null ? _a2 : config.appVersion,
673
+ appBuild: config.appBuild,
674
+ networkType: config.networkType
675
+ });
676
+ };
469
677
  const queue = createEventQueue({
470
678
  target: { serverUrl: config.serverUrl, apiKey: config.apiKey },
471
679
  storage: config.storage,
@@ -473,23 +681,48 @@ var createAnalytics = (config, options = {}) => {
473
681
  envelope,
474
682
  ...options
475
683
  });
476
- let boundUserId;
477
- const storageKey = `wireai:analytics:userId:${(_b = config.appId) != null ? _b : "default"}`;
684
+ let boundUserId = sanitizeUserId((_d = config.userContext) == null ? void 0 : _d.userId);
685
+ const storageKey = `wireai:analytics:userId:${(_e = config.appId) != null ? _e : "default"}`;
478
686
  if (config.storage) {
479
687
  void config.storage.getItem(storageKey).then((saved) => {
480
- if (saved) boundUserId = saved;
688
+ if (saved && !boundUserId) boundUserId = saved;
481
689
  }).catch(() => {
482
690
  });
483
691
  }
692
+ const applyContext = (event) => {
693
+ var _a2;
694
+ const hostDeviceKey = typeof userContext.deviceKey === "string" && userContext.deviceKey.trim() ? userContext.deviceKey : void 0;
695
+ const resolved = resolveUserContext(
696
+ { ...userContext, deviceKey: hostDeviceKey != null ? hostDeviceKey : autoDeviceKey },
697
+ { autoAppVersion: config.appVersion }
698
+ );
699
+ if (resolved.userContext) {
700
+ event.user_context = { ...resolved.userContext, ...(_a2 = event.user_context) != null ? _a2 : {} };
701
+ }
702
+ if (boundUserId && !event.user_id) event.user_id = boundUserId;
703
+ };
704
+ const setUserContext = (partial) => {
705
+ var _a2, _b2;
706
+ if (!partial || typeof partial !== "object") return;
707
+ const mergedExtra = partial.extra || userContext.extra ? { ...(_a2 = userContext.extra) != null ? _a2 : {}, ...(_b2 = partial.extra) != null ? _b2 : {} } : void 0;
708
+ userContext = { ...userContext, ...partial };
709
+ if (mergedExtra) userContext.extra = mergedExtra;
710
+ const uid = sanitizeUserId(partial.userId);
711
+ if (uid) {
712
+ boundUserId = uid;
713
+ if (config.storage) void config.storage.setItem(storageKey, uid).catch(() => {
714
+ });
715
+ }
716
+ };
484
717
  const track = (event, props) => {
485
718
  if (!event) return;
486
719
  const clientEvent = {
487
720
  event_type: "app_event",
488
- session_id: sessionId,
721
+ session_id: resolveSessionId(),
489
722
  question_key: event
490
723
  };
491
724
  if (props && Object.keys(props).length > 0) clientEvent.meta = JSON.stringify(props);
492
- if (boundUserId) clientEvent.user_id = boundUserId;
725
+ applyContext(clientEvent);
493
726
  queue.enqueue(clientEvent);
494
727
  };
495
728
  const screen = (name, props) => {
@@ -497,11 +730,11 @@ var createAnalytics = (config, options = {}) => {
497
730
  const meta = { screen: name, ...props != null ? props : {} };
498
731
  const clientEvent = {
499
732
  event_type: "app_event",
500
- session_id: sessionId,
733
+ session_id: resolveSessionId(),
501
734
  question_key: "screen",
502
735
  meta: JSON.stringify(meta)
503
736
  };
504
- if (boundUserId) clientEvent.user_id = boundUserId;
737
+ applyContext(clientEvent);
505
738
  queue.enqueue(clientEvent);
506
739
  };
507
740
  const identify = (userId, traits) => {
@@ -514,16 +747,20 @@ var createAnalytics = (config, options = {}) => {
514
747
  }
515
748
  const clientEvent = {
516
749
  event_type: "identify",
517
- session_id: sessionId,
750
+ // Reuse the LIVE per-open session id (see `resolveSessionId`) so the server binds identity to
751
+ // the session it already saw instead of back-filling a phantom `session_started`.
752
+ session_id: resolveSessionId(),
518
753
  user_id: clean
519
754
  };
520
755
  if (traits && Object.keys(traits).length > 0) clientEvent.meta = JSON.stringify(traits);
756
+ applyContext(clientEvent);
521
757
  queue.enqueue(clientEvent);
522
758
  };
523
759
  return {
524
760
  track,
525
761
  screen,
526
762
  identify,
763
+ setUserContext,
527
764
  flush: queue.flush,
528
765
  notifyOnline: queue.notifyOnline,
529
766
  size: queue.size
@@ -540,6 +777,6 @@ var useAnalytics = (config, options = {}) => {
540
777
  return ref.current;
541
778
  };
542
779
 
543
- export { WIRE_ONBOARDING_EVENTS, buildContextEnvelope, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, makeSessionId, reportAppEvent, reportClientEvent, reportClientEvents, screenTrackingHandler, toAnalyticsEvent, useAnalytics, useScreenTracking };
780
+ export { WIRE_ONBOARDING_EVENTS, buildContextEnvelope, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, getCurrentSessionId, makeSessionId, reportAppEvent, reportClientEvent, reportClientEvents, resetCurrentSessionId, screenTrackingHandler, setCurrentSessionId, toAnalyticsEvent, useAnalytics, useScreenTracking };
544
781
  //# sourceMappingURL=index.mjs.map
545
782
  //# sourceMappingURL=index.mjs.map