@wireai/activation 0.13.6 → 0.14.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 (47) hide show
  1. package/AGENTS.md +21 -9
  2. package/CHANGELOG.md +227 -1
  3. package/INTEGRATION_PROMPT.md +7 -4
  4. package/README.md +15 -2
  5. package/dist/analytics/index.d.mts +9 -2
  6. package/dist/analytics/index.d.ts +9 -2
  7. package/dist/analytics/index.js +56 -12
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +56 -12
  10. package/dist/analytics/index.mjs.map +1 -1
  11. package/dist/{currentSession-DngW-QoD.d.mts → currentSession-CUvTOchb.d.mts} +35 -6
  12. package/dist/{currentSession-C5976akx.d.ts → currentSession-CW_5Mq4O.d.ts} +35 -6
  13. package/dist/index.d.mts +31 -7
  14. package/dist/index.d.ts +31 -7
  15. package/dist/index.js +643 -539
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +643 -539
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/questionnaire/index.js +14 -6
  20. package/dist/questionnaire/index.js.map +1 -1
  21. package/dist/questionnaire/index.mjs +14 -6
  22. package/dist/questionnaire/index.mjs.map +1 -1
  23. package/dist/reviews/index.js +14 -6
  24. package/dist/reviews/index.js.map +1 -1
  25. package/dist/reviews/index.mjs +14 -6
  26. package/dist/reviews/index.mjs.map +1 -1
  27. package/llms.txt +2 -2
  28. package/package.json +1 -1
  29. package/src/OnboardingFlow.tsx +4 -3
  30. package/src/WireOnboarding.tsx +48 -8
  31. package/src/activation/useWireActivation.ts +14 -1
  32. package/src/activation/wireActivation.ts +68 -2
  33. package/src/analytics/analyticsFacade.ts +24 -0
  34. package/src/analytics/currentSession.ts +3 -2
  35. package/src/analytics/eventQueue.ts +106 -11
  36. package/src/analytics/reportClientEvent.ts +31 -7
  37. package/src/analytics/useAnalytics.ts +17 -0
  38. package/src/context/deviceId.ts +10 -3
  39. package/src/permissions/permissionMemory.ts +41 -5
  40. package/src/reviews/runtime.ts +75 -23
  41. package/src/session/persistedSession.ts +32 -8
  42. package/src/session-analytics/lifecycle.ts +26 -5
  43. package/src/session-analytics/reportSessionStart.ts +14 -10
  44. package/src/session-analytics/useLifecycleEvents.ts +70 -32
  45. package/src/session-analytics/useSessionStart.ts +57 -15
  46. package/src/types.ts +16 -6
  47. package/src/utils/readPlan.ts +8 -5
@@ -74,20 +74,21 @@ var reportClientEvents = (target, events) => {
74
74
  }
75
75
  };
76
76
  var reportClientEvent = (target, event) => reportClientEvents(target, [event]);
77
- var reportClientEventsAwait = async (target, events) => {
77
+ var reportClientEventsAwait = async (target, events) => await reportClientEventsOutcome(target, events) === "delivered";
78
+ var reportClientEventsOutcome = async (target, events) => {
78
79
  try {
79
80
  const req = buildEventsRequest(target, events);
80
- if (!req) return false;
81
+ if (!req) return "refused";
81
82
  const res = await fetch(req.url, req.init);
82
- if (!res || !res.ok) return false;
83
+ if (!res || !res.ok) return "unreachable";
83
84
  const ack = await readEventsAck(res);
84
- if (!ack || ack.skipped <= 0) return true;
85
+ if (!ack || ack.skipped <= 0) return "delivered";
85
86
  if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
86
87
  console.warn(describeDiscarded(ack));
87
88
  }
88
- return false;
89
+ return "refused";
89
90
  } catch {
90
- return false;
91
+ return "unreachable";
91
92
  }
92
93
  };
93
94
  var reportClientEventAwait = (target, event) => reportClientEventsAwait(target, [event]);
@@ -690,6 +691,9 @@ var claimQueueKey = (preferred, explicit) => {
690
691
  );
691
692
  return key;
692
693
  };
694
+ var releaseQueueKey = (key) => {
695
+ claimedQueueKeys().delete(key);
696
+ };
693
697
  var resetEventQueueKeys = () => claimedQueueKeys().clear();
694
698
  var READ_TIMED_OUT = /* @__PURE__ */ Symbol("wireai:storage-read-timeout");
695
699
  var withTimeout = (p, ms) => {
@@ -735,7 +739,8 @@ var createEventQueue = (options) => {
735
739
  let flushing = false;
736
740
  let attempt = 0;
737
741
  let retryTimer;
738
- let backlogUnread = false;
742
+ let disposed = false;
743
+ let backlogUnread = storage !== void 0;
739
744
  const resolveEnvelope = () => {
740
745
  try {
741
746
  return typeof options.envelope === "function" ? options.envelope() : options.envelope;
@@ -760,6 +765,7 @@ var createEventQueue = (options) => {
760
765
  };
761
766
  const persist = () => {
762
767
  if (!storage) return;
768
+ if (disposed) return;
763
769
  if (backlogUnread) return;
764
770
  try {
765
771
  if (pending.length === 0) {
@@ -773,8 +779,20 @@ var createEventQueue = (options) => {
773
779
  } catch {
774
780
  }
775
781
  };
782
+ const isCountedOpenEvent = (event) => typeof event.question_key === "string" && event.question_key.startsWith("app.");
776
783
  const enforceSizeCap = () => {
777
- if (pending.length > maxSize) pending.splice(0, pending.length - maxSize);
784
+ let overflow = pending.length - maxSize;
785
+ if (overflow <= 0) return;
786
+ const kept = [];
787
+ for (const item of pending) {
788
+ if (overflow > 0 && !isCountedOpenEvent(item.event)) {
789
+ overflow--;
790
+ continue;
791
+ }
792
+ kept.push(item);
793
+ }
794
+ if (overflow > 0) kept.splice(0, overflow);
795
+ pending = kept;
778
796
  };
779
797
  const safeSig = (event) => {
780
798
  try {
@@ -820,8 +838,12 @@ var createEventQueue = (options) => {
820
838
  });
821
839
  return;
822
840
  }
841
+ backlogUnread = false;
823
842
  mergePersisted(parsePersisted(raced));
843
+ persist();
824
844
  } catch {
845
+ backlogUnread = false;
846
+ persist();
825
847
  }
826
848
  })();
827
849
  const postBatch = async (events) => {
@@ -857,10 +879,12 @@ var createEventQueue = (options) => {
857
879
  unrefTimer(retryTimer);
858
880
  };
859
881
  const drain = async () => {
882
+ if (disposed) return;
860
883
  try {
861
884
  await loadPromise;
862
885
  } catch {
863
886
  }
887
+ if (disposed) return;
864
888
  if (flushing) return;
865
889
  flushing = true;
866
890
  try {
@@ -888,6 +912,7 @@ var createEventQueue = (options) => {
888
912
  }
889
913
  };
890
914
  const enqueue = (event) => {
915
+ if (disposed) return;
891
916
  try {
892
917
  const stamped = stamp(event);
893
918
  const sig = safeSig(stamped);
@@ -907,7 +932,13 @@ var createEventQueue = (options) => {
907
932
  flush();
908
933
  };
909
934
  const size = () => pending.length;
910
- return { enqueue, flush, notifyOnline, size };
935
+ const dispose = () => {
936
+ if (disposed) return;
937
+ disposed = true;
938
+ clearRetry();
939
+ if (storage) releaseQueueKey(key);
940
+ };
941
+ return { enqueue, flush, notifyOnline, size, dispose };
911
942
  };
912
943
 
913
944
  // src/identity/userIdentity.ts
@@ -1145,8 +1176,10 @@ var createAnalytics = (config, options = {}) => {
1145
1176
  });
1146
1177
  let boundUserId = sanitizeUserId((_c = config.userContext) == null ? void 0 : _c.userId);
1147
1178
  const storageKey = analyticsUserIdStorageKey(config.appId);
1179
+ let hydrationSuperseded = false;
1148
1180
  if (config.storage) {
1149
1181
  void config.storage.getItem(storageKey).then((saved) => {
1182
+ if (hydrationSuperseded) return;
1150
1183
  if (saved && !boundUserId) boundUserId = saved;
1151
1184
  }).catch(() => {
1152
1185
  });
@@ -1188,6 +1221,7 @@ var createAnalytics = (config, options = {}) => {
1188
1221
  }
1189
1222
  };
1190
1223
  const reset = () => {
1224
+ hydrationSuperseded = true;
1191
1225
  boundUserId = void 0;
1192
1226
  userContext = clearPiiFromContext(userContext);
1193
1227
  if (config.storage) void config.storage.removeItem(storageKey).catch(() => {
@@ -1245,23 +1279,33 @@ var createAnalytics = (config, options = {}) => {
1245
1279
  reset,
1246
1280
  flush: queue.flush,
1247
1281
  notifyOnline: queue.notifyOnline,
1248
- size: queue.size
1282
+ size: queue.size,
1283
+ dispose: queue.dispose
1249
1284
  };
1250
1285
  };
1251
1286
  var useAnalytics = (config, options = {}) => {
1252
- var _a;
1287
+ var _a, _b;
1253
1288
  const ref = useRef(void 0);
1254
1289
  const prevKeys = useRef("");
1255
1290
  const currentKeys = `${config.serverUrl}|${config.apiKey}|${config.appId}`;
1256
1291
  if (!ref.current || prevKeys.current !== currentKeys) {
1257
1292
  prevKeys.current = currentKeys;
1293
+ (_a = ref.current) == null ? void 0 : _a.dispose();
1258
1294
  ref.current = createAnalytics(config, options);
1259
1295
  }
1260
- const hostDeviceKey = typeof ((_a = config.userContext) == null ? void 0 : _a.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
1296
+ const hostDeviceKey = typeof ((_b = config.userContext) == null ? void 0 : _b.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
1261
1297
  useEffect(() => {
1262
1298
  var _a2;
1263
1299
  if (hostDeviceKey) (_a2 = ref.current) == null ? void 0 : _a2.setUserContext({ deviceKey: hostDeviceKey });
1264
1300
  }, [hostDeviceKey]);
1301
+ useEffect(
1302
+ () => () => {
1303
+ var _a2;
1304
+ (_a2 = ref.current) == null ? void 0 : _a2.dispose();
1305
+ ref.current = void 0;
1306
+ },
1307
+ []
1308
+ );
1265
1309
  return ref.current;
1266
1310
  };
1267
1311