@wireai/activation 0.11.0 → 0.12.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 (73) hide show
  1. package/AGENTS.md +62 -8
  2. package/CHANGELOG.md +188 -3
  3. package/INTEGRATION_PROMPT.md +25 -2
  4. package/README.md +112 -1
  5. package/dist/analytics/index.d.mts +18 -6
  6. package/dist/analytics/index.d.ts +18 -6
  7. package/dist/analytics/index.js +151 -41
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +147 -42
  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-C0_odnIW.d.mts → currentSession-BlCeDP0f.d.mts} +145 -33
  18. package/dist/{currentSession-DdnUq2HQ.d.ts → currentSession-BxEB37xt.d.ts} +145 -33
  19. package/dist/index.d.mts +243 -53
  20. package/dist/index.d.ts +243 -53
  21. package/dist/index.js +531 -156
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +517 -157
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/questionnaire/index.d.mts +1 -1
  26. package/dist/questionnaire/index.d.ts +1 -1
  27. package/dist/questionnaire/index.js +79 -14
  28. package/dist/questionnaire/index.js.map +1 -1
  29. package/dist/questionnaire/index.mjs +79 -14
  30. package/dist/questionnaire/index.mjs.map +1 -1
  31. package/dist/reviews/index.d.mts +2 -2
  32. package/dist/reviews/index.d.ts +2 -2
  33. package/dist/reviews/index.js +103 -16
  34. package/dist/reviews/index.js.map +1 -1
  35. package/dist/reviews/index.mjs +103 -16
  36. package/dist/reviews/index.mjs.map +1 -1
  37. package/dist/showcase/index.js +15 -6
  38. package/dist/showcase/index.js.map +1 -1
  39. package/dist/showcase/index.mjs +15 -6
  40. package/dist/showcase/index.mjs.map +1 -1
  41. package/dist/{transport-BGW9uXZJ.d.mts → transport-CF_eHwzC.d.mts} +15 -1
  42. package/dist/{transport-jUJd5kxu.d.ts → transport-DsRe4epC.d.ts} +15 -1
  43. package/llms.txt +3 -0
  44. package/package.json +1 -1
  45. package/src/WireOnboarding.tsx +140 -5
  46. package/src/activation/useWireActivation.ts +12 -1
  47. package/src/activation/wireActivation.ts +44 -25
  48. package/src/analytics/analyticsFacade.ts +54 -29
  49. package/src/analytics/currentSession.ts +83 -0
  50. package/src/analytics/eventQueue.ts +9 -1
  51. package/src/analytics/index.ts +20 -1
  52. package/src/analytics/reportClientEvent.ts +42 -0
  53. package/src/analytics/screenTracking.ts +6 -1
  54. package/src/analytics/useAnalytics.ts +22 -1
  55. package/src/coachmarks/runtime.ts +53 -17
  56. package/src/config/wireConfigFromEnv.ts +46 -2
  57. package/src/context/deviceId.ts +173 -0
  58. package/src/context/userContext.ts +18 -0
  59. package/src/index.ts +54 -2
  60. package/src/questionnaire/runtime.ts +13 -2
  61. package/src/questionnaire/useQuestionnaireGate.ts +11 -4
  62. package/src/revenuecat/index.ts +55 -0
  63. package/src/revenuecat/purchaseEvents.ts +167 -0
  64. package/src/revenuecat/revenueCatBridge.ts +221 -0
  65. package/src/revenuecat/types.ts +95 -0
  66. package/src/reviews/runtime.ts +153 -1
  67. package/src/reviews/transport.ts +21 -2
  68. package/src/reviews/useReviewGate.ts +14 -4
  69. package/src/session-analytics/lifecycle.ts +9 -2
  70. package/src/session-analytics/reportSessionStart.ts +15 -4
  71. package/src/session-analytics/useLifecycleEvents.ts +83 -27
  72. package/src/session-analytics/useSessionStart.ts +37 -1
  73. package/src/types.ts +41 -4
@@ -290,7 +290,7 @@ declare const fetchQuestionnaireDecision: (target: QuestionnaireTarget | undefin
290
290
  declare const questionnaireSeenKey: (id: string, version?: string) => string;
291
291
  /** Last-shown timestamp key (epoch ms), for the cooldown rule. */
292
292
  declare const questionnaireLastShownKey: (id: string) => string;
293
- /** Session-count key, incremented once per gate mount, for the min-sessions rule. */
293
+ /** Session-count key, incremented once per APP-OPEN (not per mount), for the min-sessions rule. */
294
294
  declare const questionnaireSessionsKey: (id: string) => string;
295
295
 
296
296
  export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireTarget, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
@@ -290,7 +290,7 @@ declare const fetchQuestionnaireDecision: (target: QuestionnaireTarget | undefin
290
290
  declare const questionnaireSeenKey: (id: string, version?: string) => string;
291
291
  /** Last-shown timestamp key (epoch ms), for the cooldown rule. */
292
292
  declare const questionnaireLastShownKey: (id: string) => string;
293
- /** Session-count key, incremented once per gate mount, for the min-sessions rule. */
293
+ /** Session-count key, incremented once per APP-OPEN (not per mount), for the min-sessions rule. */
294
294
  declare const questionnaireSessionsKey: (id: string) => string;
295
295
 
296
296
  export { type FetchQuestionnaireDecisionOptions, type QuestionnaireAnswers, type QuestionnaireDecision, type QuestionnaireDecisionResponse, type QuestionnaireDefinition, QuestionnaireGate, type QuestionnaireGateController, type QuestionnaireGateEvent, type QuestionnaireGateEventName, type QuestionnaireGateProps, type QuestionnaireMeta, type QuestionnaireSubmission, type QuestionnaireTarget, type UseQuestionnaireGateOptions, buildQuestionnaireSubmission, decideQuestionnaire, fetchQuestionnaireDecision, questionnaireLastShownKey, questionnaireSeenKey, questionnaireSessionsKey, submitQuestionnaireResponse, useQuestionnaireGate };
@@ -1091,14 +1091,21 @@ var styles7 = reactNative.StyleSheet.create({
1091
1091
  });
1092
1092
 
1093
1093
  // src/coachmarks/runtime.ts
1094
- var storageSingleton = null;
1095
- var testing = false;
1096
- var getCoachmarkStorage = () => storageSingleton;
1097
- var isCoachmarkTesting = () => testing;
1094
+ var COACHMARK_RUNTIME_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:coachmarkRuntime");
1095
+ var runtimeGlobal = globalThis;
1096
+ var coachmarkRuntime = () => {
1097
+ const existing = runtimeGlobal[COACHMARK_RUNTIME_SLOT];
1098
+ if (existing) return existing;
1099
+ const created = { storage: null, testing: false, coachmarksEnabled: true };
1100
+ runtimeGlobal[COACHMARK_RUNTIME_SLOT] = created;
1101
+ return created;
1102
+ };
1103
+ var getCoachmarkStorage = () => coachmarkRuntime().storage;
1104
+ var isCoachmarkTesting = () => coachmarkRuntime().testing;
1098
1105
  var SEEN_VALUE = "1";
1099
1106
  var hasSeenGate = (key, storageOverride, testingOverride) => {
1100
- if (testingOverride != null ? testingOverride : testing) return false;
1101
- const storage = storageOverride != null ? storageOverride : storageSingleton;
1107
+ if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return false;
1108
+ const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
1102
1109
  if (!storage) return false;
1103
1110
  try {
1104
1111
  return storage.getItem(key) === SEEN_VALUE;
@@ -1107,8 +1114,8 @@ var hasSeenGate = (key, storageOverride, testingOverride) => {
1107
1114
  }
1108
1115
  };
1109
1116
  var markSeenGate = (key, storageOverride, testingOverride) => {
1110
- if (testingOverride != null ? testingOverride : testing) return;
1111
- const storage = storageOverride != null ? storageOverride : storageSingleton;
1117
+ if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return;
1118
+ const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
1112
1119
  if (!storage) return;
1113
1120
  try {
1114
1121
  storage.setItem(key, SEEN_VALUE);
@@ -1290,8 +1297,32 @@ var sameDecision = (a, b) => {
1290
1297
  return a.fire === b.fire && a.reason === b.reason;
1291
1298
  };
1292
1299
 
1300
+ // src/analytics/reportClientEvent.ts
1301
+ var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
1302
+
1303
+ // src/analytics/currentSession.ts
1304
+ var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
1305
+ "@wireai/activation:currentSessionId"
1306
+ );
1307
+ var globalSlot = globalThis;
1308
+ var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
1309
+
1293
1310
  // src/reviews/runtime.ts
1294
1311
  var resolveStorage = (override) => override != null ? override : getCoachmarkStorage();
1312
+ var NO_STORAGE_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
1313
+ "@wireai/activation:gateStorageWarned"
1314
+ );
1315
+ var gateWarnGlobal = globalThis;
1316
+ var warnMissingGateStorage = (storage, gate) => {
1317
+ if (storage) return;
1318
+ if (gateWarnGlobal[NO_STORAGE_WARNED_SLOT]) return;
1319
+ if (typeof __DEV__ === "undefined" || !__DEV__) return;
1320
+ if (typeof console === "undefined" || !console.warn) return;
1321
+ gateWarnGlobal[NO_STORAGE_WARNED_SLOT] = true;
1322
+ console.warn(
1323
+ `[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.`
1324
+ );
1325
+ };
1295
1326
  var readInt = (storage, key) => {
1296
1327
  if (!storage) return 0;
1297
1328
  try {
@@ -1309,11 +1340,45 @@ var writeInt = (storage, key, value) => {
1309
1340
  } catch {
1310
1341
  }
1311
1342
  };
1343
+ var readStr = (storage, key) => {
1344
+ if (!storage) return void 0;
1345
+ try {
1346
+ const raw = storage.getItem(key);
1347
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
1348
+ } catch {
1349
+ return void 0;
1350
+ }
1351
+ };
1352
+ var PROCESS_OPEN_ID_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:processOpenId");
1353
+ var openIdGlobal = globalThis;
1354
+ var currentOpenId = () => {
1355
+ var _a;
1356
+ const existing = openIdGlobal[PROCESS_OPEN_ID_SLOT];
1357
+ if (existing) return existing;
1358
+ const resolved = (_a = getCurrentSessionId()) != null ? _a : makeSessionId();
1359
+ openIdGlobal[PROCESS_OPEN_ID_SLOT] = resolved;
1360
+ return resolved;
1361
+ };
1362
+ var bumpSessionCount = (storage, sessionsKey, openKey, openId = currentOpenId()) => {
1363
+ const lastOpen = readStr(storage, openKey);
1364
+ const stored = readInt(storage, sessionsKey);
1365
+ if (lastOpen === openId) return stored > 0 ? stored : 1;
1366
+ const next = stored + 1;
1367
+ writeInt(storage, sessionsKey, next);
1368
+ if (storage) {
1369
+ try {
1370
+ storage.setItem(openKey, openId);
1371
+ } catch {
1372
+ }
1373
+ }
1374
+ return next;
1375
+ };
1312
1376
 
1313
1377
  // src/questionnaire/runtime.ts
1314
1378
  var questionnaireSeenKey = (id, version) => version ? `wire_questionnaire_${id}_${version}_seen` : `wire_questionnaire_${id}_seen`;
1315
1379
  var questionnaireLastShownKey = (id) => `wire_questionnaire_${id}_last`;
1316
1380
  var questionnaireSessionsKey = (id) => `wire_questionnaire_${id}_sessions`;
1381
+ var questionnaireSessionOpenKey = (id) => `wire_questionnaire_${id}_open`;
1317
1382
 
1318
1383
  // src/questionnaire/useQuestionnaireGate.ts
1319
1384
  var useStableValue2 = (value, isEqual) => {
@@ -1333,18 +1398,18 @@ var useQuestionnaireGate = ({
1333
1398
  const config = useStableValue2(configProp, shallowEqual);
1334
1399
  const decision = useStableValue2(decisionProp, (a, b) => sameDecision(a, b));
1335
1400
  const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig }).questionnaire.enabled;
1336
- const testing2 = isTesting != null ? isTesting : isCoachmarkTesting();
1401
+ const testing = isTesting != null ? isTesting : isCoachmarkTesting();
1337
1402
  const seenKey = questionnaireSeenKey(
1338
1403
  config.id,
1339
1404
  config.oncePerVersion === false ? void 0 : config.appVersion
1340
1405
  );
1341
1406
  const lastKey = questionnaireLastShownKey(config.id);
1342
1407
  const sessionsKey = questionnaireSessionsKey(config.id);
1408
+ const sessionOpenKey = questionnaireSessionOpenKey(config.id);
1343
1409
  const sessions = React8.useState(() => {
1344
1410
  const store = resolveStorage(storage);
1345
- const next = readInt(store, sessionsKey) + 1;
1346
- writeInt(store, sessionsKey, next);
1347
- return next;
1411
+ warnMissingGateStorage(store, "questionnaire");
1412
+ return bumpSessionCount(store, sessionsKey, sessionOpenKey);
1348
1413
  })[0];
1349
1414
  const hasServerDecision = decision != null;
1350
1415
  const timeoutMs = config.timeoutFallbackMs;
@@ -1364,7 +1429,7 @@ var useQuestionnaireGate = ({
1364
1429
  visible: false,
1365
1430
  verdict: { fire: false, reason: "feature_disabled" }
1366
1431
  };
1367
- if (testing2)
1432
+ if (testing)
1368
1433
  return {
1369
1434
  visible: true,
1370
1435
  verdict: { fire: true, reason: "testing" }
@@ -1383,7 +1448,7 @@ var useQuestionnaireGate = ({
1383
1448
  return { visible: ready && resolved.fire && !alreadySeen, verdict: resolved };
1384
1449
  }, [
1385
1450
  featureEnabled,
1386
- testing2,
1451
+ testing,
1387
1452
  config,
1388
1453
  decision,
1389
1454
  events,