@wireai/activation 0.10.0 → 0.12.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 (61) hide show
  1. package/AGENTS.md +51 -0
  2. package/CHANGELOG.md +111 -1
  3. package/INTEGRATION_PROMPT.md +13 -1
  4. package/README.md +106 -4
  5. package/dist/analytics/index.d.mts +35 -6
  6. package/dist/analytics/index.d.ts +35 -6
  7. package/dist/analytics/index.js +222 -94
  8. package/dist/analytics/index.js.map +1 -1
  9. package/dist/analytics/index.mjs +214 -95
  10. package/dist/analytics/index.mjs.map +1 -1
  11. package/dist/{currentSession-D0Vq7_VE.d.ts → currentSession-D6RiVtc8.d.ts} +187 -29
  12. package/dist/{currentSession-DdDkprpM.d.mts → currentSession-DsSDHqor.d.mts} +187 -29
  13. package/dist/index.d.mts +236 -82
  14. package/dist/index.d.ts +236 -82
  15. package/dist/index.js +330 -60
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +314 -61
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/questionnaire/index.d.mts +1 -1
  20. package/dist/questionnaire/index.d.ts +1 -1
  21. package/dist/questionnaire/index.js +59 -8
  22. package/dist/questionnaire/index.js.map +1 -1
  23. package/dist/questionnaire/index.mjs +59 -8
  24. package/dist/questionnaire/index.mjs.map +1 -1
  25. package/dist/reviews/index.d.mts +2 -2
  26. package/dist/reviews/index.d.ts +2 -2
  27. package/dist/reviews/index.js +97 -17
  28. package/dist/reviews/index.js.map +1 -1
  29. package/dist/reviews/index.mjs +97 -17
  30. package/dist/reviews/index.mjs.map +1 -1
  31. package/dist/{transport-Bzb-bcB2.d.mts → transport-CF_eHwzC.d.mts} +15 -16
  32. package/dist/{transport-B31G0Cib.d.ts → transport-DsRe4epC.d.ts} +15 -16
  33. package/llms.txt +9 -0
  34. package/package.json +1 -1
  35. package/src/activation/useWireActivation.ts +12 -1
  36. package/src/activation/wireActivation.ts +36 -24
  37. package/src/analytics/analyticsFacade.ts +113 -29
  38. package/src/analytics/currentSession.ts +83 -0
  39. package/src/analytics/eventQueue.ts +20 -11
  40. package/src/analytics/index.ts +29 -1
  41. package/src/analytics/reportClientEvent.ts +50 -2
  42. package/src/analytics/screenTracking.ts +6 -1
  43. package/src/analytics/useAnalytics.ts +22 -1
  44. package/src/context/deviceId.ts +109 -0
  45. package/src/context/userContext.ts +73 -0
  46. package/src/identity/userIdentity.ts +10 -0
  47. package/src/index.ts +50 -2
  48. package/src/questionnaire/runtime.ts +12 -2
  49. package/src/questionnaire/transport.ts +5 -1
  50. package/src/questionnaire/useQuestionnaireGate.ts +9 -7
  51. package/src/revenuecat/index.ts +55 -0
  52. package/src/revenuecat/purchaseEvents.ts +167 -0
  53. package/src/revenuecat/revenueCatBridge.ts +221 -0
  54. package/src/revenuecat/types.ts +95 -0
  55. package/src/reviews/decision.ts +8 -1
  56. package/src/reviews/runtime.ts +92 -1
  57. package/src/reviews/transport.ts +27 -10
  58. package/src/reviews/useReviewGate.ts +12 -7
  59. package/src/session-analytics/lifecycle.ts +15 -13
  60. package/src/session-analytics/reportSessionStart.ts +15 -4
  61. package/src/session-analytics/useLifecycleEvents.ts +68 -28
@@ -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 };
@@ -704,7 +704,14 @@ var resolveRules = (config) => {
704
704
  var _a, _b, _c, _d, _e;
705
705
  return {
706
706
  enabled: (_a = config.enabled) != null ? _a : true,
707
- minSessions: (_b = config.minSessions) != null ? _b : 0,
707
+ // FAIL-CLOSED on the first session (behavior change, 0.11.0). An unconfigured host with no
708
+ // server decision must NOT prompt on the very first mount: `minSessions` defaults to 2 so the
709
+ // gate needs at least a second session before the LOCAL rules can fire. This is the client-side
710
+ // floor only — a server `decision` (from `fetchReviewDecision`) still OVERRIDES everything, and a
711
+ // host that genuinely wants first-session prompting can set `minSessions: 1` (or `0`) explicitly.
712
+ // Mirrors the 2026-07-16 incident: a first-session user, no server decision, got the prompt and
713
+ // left 1 star. See `evaluateGate` (`min_sessions` reason) and the CHANGELOG.
714
+ minSessions: (_b = config.minSessions) != null ? _b : 2,
708
715
  minEvents: (_c = config.minEvents) != null ? _c : 0,
709
716
  cooldownDays: (_d = config.cooldownDays) != null ? _d : 0,
710
717
  oncePerVersion: (_e = config.oncePerVersion) != null ? _e : true
@@ -862,7 +869,8 @@ var fetchQuestionnaireDecision = async (target, options = {}) => {
862
869
  const res = await fetch(url, { headers });
863
870
  if (!res || !res.ok) return null;
864
871
  const json = await res.json();
865
- return json != null ? json : null;
872
+ if (!json || typeof json.fire !== "boolean") return null;
873
+ return json;
866
874
  } catch {
867
875
  return null;
868
876
  }
@@ -1282,6 +1290,16 @@ var sameDecision = (a, b) => {
1282
1290
  return a.fire === b.fire && a.reason === b.reason;
1283
1291
  };
1284
1292
 
1293
+ // src/analytics/reportClientEvent.ts
1294
+ var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
1295
+
1296
+ // src/analytics/currentSession.ts
1297
+ var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
1298
+ "@wireai/activation:currentSessionId"
1299
+ );
1300
+ var globalSlot = globalThis;
1301
+ var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
1302
+
1285
1303
  // src/reviews/runtime.ts
1286
1304
  var resolveStorage = (override) => override != null ? override : getCoachmarkStorage();
1287
1305
  var readInt = (storage, key) => {
@@ -1301,11 +1319,46 @@ var writeInt = (storage, key, value) => {
1301
1319
  } catch {
1302
1320
  }
1303
1321
  };
1322
+ var readStr = (storage, key) => {
1323
+ if (!storage) return void 0;
1324
+ try {
1325
+ const raw = storage.getItem(key);
1326
+ return typeof raw === "string" && raw.length > 0 ? raw : void 0;
1327
+ } catch {
1328
+ return void 0;
1329
+ }
1330
+ };
1331
+ var PROCESS_OPEN_ID_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:processOpenId");
1332
+ var openIdGlobal = globalThis;
1333
+ var currentOpenId = () => {
1334
+ const live = getCurrentSessionId();
1335
+ if (live) return live;
1336
+ const existing = openIdGlobal[PROCESS_OPEN_ID_SLOT];
1337
+ if (existing) return existing;
1338
+ const created = makeSessionId();
1339
+ openIdGlobal[PROCESS_OPEN_ID_SLOT] = created;
1340
+ return created;
1341
+ };
1342
+ var bumpSessionCount = (storage, sessionsKey, openKey, openId = currentOpenId()) => {
1343
+ const lastOpen = readStr(storage, openKey);
1344
+ const stored = readInt(storage, sessionsKey);
1345
+ if (lastOpen === openId) return stored > 0 ? stored : 1;
1346
+ const next = stored + 1;
1347
+ writeInt(storage, sessionsKey, next);
1348
+ if (storage) {
1349
+ try {
1350
+ storage.setItem(openKey, openId);
1351
+ } catch {
1352
+ }
1353
+ }
1354
+ return next;
1355
+ };
1304
1356
 
1305
1357
  // src/questionnaire/runtime.ts
1306
1358
  var questionnaireSeenKey = (id, version) => version ? `wire_questionnaire_${id}_${version}_seen` : `wire_questionnaire_${id}_seen`;
1307
1359
  var questionnaireLastShownKey = (id) => `wire_questionnaire_${id}_last`;
1308
1360
  var questionnaireSessionsKey = (id) => `wire_questionnaire_${id}_sessions`;
1361
+ var questionnaireSessionOpenKey = (id) => `wire_questionnaire_${id}_open`;
1309
1362
 
1310
1363
  // src/questionnaire/useQuestionnaireGate.ts
1311
1364
  var useStableValue2 = (value, isEqual) => {
@@ -1332,12 +1385,10 @@ var useQuestionnaireGate = ({
1332
1385
  );
1333
1386
  const lastKey = questionnaireLastShownKey(config.id);
1334
1387
  const sessionsKey = questionnaireSessionsKey(config.id);
1335
- const sessions = React8.useState(() => {
1336
- const store = resolveStorage(storage);
1337
- const next = readInt(store, sessionsKey) + 1;
1338
- writeInt(store, sessionsKey, next);
1339
- return next;
1340
- })[0];
1388
+ const sessionOpenKey = questionnaireSessionOpenKey(config.id);
1389
+ const sessions = React8.useState(
1390
+ () => bumpSessionCount(resolveStorage(storage), sessionsKey, sessionOpenKey)
1391
+ )[0];
1341
1392
  const hasServerDecision = decision != null;
1342
1393
  const timeoutMs = config.timeoutFallbackMs;
1343
1394
  const waits = !hasServerDecision && timeoutMs != null && timeoutMs > 0;