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