@wireai/activation 0.12.0 → 0.12.2

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 (53) hide show
  1. package/AGENTS.md +13 -10
  2. package/CHANGELOG.md +130 -0
  3. package/INTEGRATION_PROMPT.md +14 -3
  4. package/README.md +40 -2
  5. package/dist/analytics/index.d.mts +5 -4
  6. package/dist/analytics/index.d.ts +5 -4
  7. package/dist/analytics/index.js +39 -24
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +39 -24
  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-DsSDHqor.d.mts → currentSession-BlCeDP0f.d.mts} +59 -5
  18. package/dist/{currentSession-D6RiVtc8.d.ts → currentSession-BxEB37xt.d.ts} +59 -5
  19. package/dist/index.d.mts +10 -20
  20. package/dist/index.d.ts +10 -20
  21. package/dist/index.js +301 -187
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +300 -188
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/questionnaire/index.js +41 -19
  26. package/dist/questionnaire/index.js.map +1 -1
  27. package/dist/questionnaire/index.mjs +41 -19
  28. package/dist/questionnaire/index.mjs.map +1 -1
  29. package/dist/reviews/index.js +41 -19
  30. package/dist/reviews/index.js.map +1 -1
  31. package/dist/reviews/index.mjs +41 -19
  32. package/dist/reviews/index.mjs.map +1 -1
  33. package/dist/showcase/index.js +15 -6
  34. package/dist/showcase/index.js.map +1 -1
  35. package/dist/showcase/index.mjs +15 -6
  36. package/dist/showcase/index.mjs.map +1 -1
  37. package/llms.txt +2 -0
  38. package/package.json +1 -1
  39. package/src/WireOnboarding.tsx +140 -5
  40. package/src/activation/wireActivation.ts +8 -1
  41. package/src/analytics/analyticsFacade.ts +15 -11
  42. package/src/analytics/reportClientEvent.ts +11 -7
  43. package/src/coachmarks/runtime.ts +53 -17
  44. package/src/config/wireConfigFromEnv.ts +46 -2
  45. package/src/context/deviceId.ts +82 -18
  46. package/src/index.ts +9 -1
  47. package/src/questionnaire/runtime.ts +1 -0
  48. package/src/questionnaire/useQuestionnaireGate.ts +8 -3
  49. package/src/reviews/runtime.ts +68 -7
  50. package/src/reviews/useReviewGate.ts +8 -3
  51. package/src/session-analytics/useLifecycleEvents.ts +57 -27
  52. package/src/session-analytics/useSessionStart.ts +37 -1
  53. package/src/types.ts +41 -4
@@ -1087,14 +1087,21 @@ var styles6 = reactNative.StyleSheet.create({
1087
1087
  });
1088
1088
 
1089
1089
  // src/coachmarks/runtime.ts
1090
- var storageSingleton = null;
1091
- var testing = false;
1092
- var getCoachmarkStorage = () => storageSingleton;
1093
- var isCoachmarkTesting = () => testing;
1090
+ var COACHMARK_RUNTIME_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:coachmarkRuntime");
1091
+ var runtimeGlobal = globalThis;
1092
+ var coachmarkRuntime = () => {
1093
+ const existing = runtimeGlobal[COACHMARK_RUNTIME_SLOT];
1094
+ if (existing) return existing;
1095
+ const created = { storage: null, testing: false, coachmarksEnabled: true };
1096
+ runtimeGlobal[COACHMARK_RUNTIME_SLOT] = created;
1097
+ return created;
1098
+ };
1099
+ var getCoachmarkStorage = () => coachmarkRuntime().storage;
1100
+ var isCoachmarkTesting = () => coachmarkRuntime().testing;
1094
1101
  var SEEN_VALUE = "1";
1095
1102
  var hasSeenGate = (key, storageOverride, testingOverride) => {
1096
- if (testingOverride != null ? testingOverride : testing) return false;
1097
- const storage = storageOverride != null ? storageOverride : storageSingleton;
1103
+ if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return false;
1104
+ const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
1098
1105
  if (!storage) return false;
1099
1106
  try {
1100
1107
  return storage.getItem(key) === SEEN_VALUE;
@@ -1103,8 +1110,8 @@ var hasSeenGate = (key, storageOverride, testingOverride) => {
1103
1110
  }
1104
1111
  };
1105
1112
  var markSeenGate = (key, storageOverride, testingOverride) => {
1106
- if (testingOverride != null ? testingOverride : testing) return;
1107
- const storage = storageOverride != null ? storageOverride : storageSingleton;
1113
+ if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return;
1114
+ const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
1108
1115
  if (!storage) return;
1109
1116
  try {
1110
1117
  storage.setItem(key, SEEN_VALUE);
@@ -1292,6 +1299,20 @@ var reviewLastShownKey = (id) => `wire_review_${id}_last`;
1292
1299
  var reviewSessionsKey = (id) => `wire_review_${id}_sessions`;
1293
1300
  var reviewSessionOpenKey = (id) => `wire_review_${id}_open`;
1294
1301
  var resolveStorage = (override) => override != null ? override : getCoachmarkStorage();
1302
+ var NO_STORAGE_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
1303
+ "@wireai/activation:gateStorageWarned"
1304
+ );
1305
+ var gateWarnGlobal = globalThis;
1306
+ var warnMissingGateStorage = (storage, gate) => {
1307
+ if (storage) return;
1308
+ if (gateWarnGlobal[NO_STORAGE_WARNED_SLOT]) return;
1309
+ if (typeof __DEV__ === "undefined" || !__DEV__) return;
1310
+ if (typeof console === "undefined" || !console.warn) return;
1311
+ gateWarnGlobal[NO_STORAGE_WARNED_SLOT] = true;
1312
+ console.warn(
1313
+ `[wireai] the ${gate} gate has no sync storage, so its app-open counter is stuck at 1 and the fail-closed minSessions rule can never be satisfied \u2014 the gate will never fire. Mount CoachmarkProvider with a sync storage adapter at your app root, or pass \`storage\` to the gate.`
1314
+ );
1315
+ };
1295
1316
  var readInt = (storage, key) => {
1296
1317
  if (!storage) return 0;
1297
1318
  try {
@@ -1321,13 +1342,12 @@ var readStr = (storage, key) => {
1321
1342
  var PROCESS_OPEN_ID_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:processOpenId");
1322
1343
  var openIdGlobal = globalThis;
1323
1344
  var currentOpenId = () => {
1324
- const live = getCurrentSessionId();
1325
- if (live) return live;
1345
+ var _a;
1326
1346
  const existing = openIdGlobal[PROCESS_OPEN_ID_SLOT];
1327
1347
  if (existing) return existing;
1328
- const created = makeSessionId();
1329
- openIdGlobal[PROCESS_OPEN_ID_SLOT] = created;
1330
- return created;
1348
+ const resolved = (_a = getCurrentSessionId()) != null ? _a : makeSessionId();
1349
+ openIdGlobal[PROCESS_OPEN_ID_SLOT] = resolved;
1350
+ return resolved;
1331
1351
  };
1332
1352
  var bumpSessionCount = (storage, sessionsKey, openKey, openId = currentOpenId()) => {
1333
1353
  const lastOpen = readStr(storage, openKey);
@@ -1365,14 +1385,16 @@ var useReviewGate = ({
1365
1385
  (a, b) => sameDecision(a, b)
1366
1386
  );
1367
1387
  const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig }).review.enabled;
1368
- const testing2 = isTesting != null ? isTesting : isCoachmarkTesting();
1388
+ const testing = isTesting != null ? isTesting : isCoachmarkTesting();
1369
1389
  const seenKey = reviewSeenKey(config.id, config.oncePerVersion === false ? void 0 : config.appVersion);
1370
1390
  const lastKey = reviewLastShownKey(config.id);
1371
1391
  const sessionsKey = reviewSessionsKey(config.id);
1372
1392
  const sessionOpenKey = reviewSessionOpenKey(config.id);
1373
- const sessions = React7.useState(
1374
- () => bumpSessionCount(resolveStorage(storage), sessionsKey, sessionOpenKey)
1375
- )[0];
1393
+ const sessions = React7.useState(() => {
1394
+ const store = resolveStorage(storage);
1395
+ warnMissingGateStorage(store, "review");
1396
+ return bumpSessionCount(store, sessionsKey, sessionOpenKey);
1397
+ })[0];
1376
1398
  const hasServerDecision = decision != null;
1377
1399
  const timeoutMs = config.timeoutFallbackMs;
1378
1400
  const waits = !hasServerDecision && timeoutMs != null && timeoutMs > 0;
@@ -1387,7 +1409,7 @@ var useReviewGate = ({
1387
1409
  }, [waits, timeoutMs]);
1388
1410
  const { visible, verdict } = React7.useMemo(() => {
1389
1411
  if (!featureEnabled) return { visible: false, verdict: { fire: false, reason: "feature_disabled" } };
1390
- if (testing2) return { visible: true, verdict: { fire: true, reason: "testing" } };
1412
+ if (testing) return { visible: true, verdict: { fire: true, reason: "testing" } };
1391
1413
  const store = resolveStorage(storage);
1392
1414
  const local = evaluateGate(resolveRules(config), {
1393
1415
  sessions,
@@ -1400,7 +1422,7 @@ var useReviewGate = ({
1400
1422
  const alreadySeen = hasSeenGate(seenKey, storage, isTesting);
1401
1423
  const ready = hasServerDecision || elapsed;
1402
1424
  return { visible: ready && resolved.fire && !alreadySeen, verdict: resolved };
1403
- }, [featureEnabled, testing2, config, decision, events, sessions, elapsed, hasServerDecision, seenKey, lastKey, storage, isTesting]);
1425
+ }, [featureEnabled, testing, config, decision, events, sessions, elapsed, hasServerDecision, seenKey, lastKey, storage, isTesting]);
1404
1426
  const shownRef = React7.useRef(false);
1405
1427
  const markShown = React7.useCallback(() => {
1406
1428
  if (shownRef.current) return;