@wireai/activation 0.11.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.
- package/AGENTS.md +51 -0
- package/CHANGELOG.md +58 -3
- package/INTEGRATION_PROMPT.md +13 -1
- package/README.md +73 -0
- package/dist/analytics/index.d.mts +17 -6
- package/dist/analytics/index.d.ts +17 -6
- package/dist/analytics/index.js +130 -35
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +126 -36
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/{currentSession-DdnUq2HQ.d.ts → currentSession-D6RiVtc8.d.ts} +88 -30
- package/dist/{currentSession-C0_odnIW.d.mts → currentSession-DsSDHqor.d.mts} +88 -30
- package/dist/index.d.mts +236 -36
- package/dist/index.d.ts +236 -36
- package/dist/index.js +281 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +269 -21
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +1 -1
- package/dist/questionnaire/index.d.ts +1 -1
- package/dist/questionnaire/index.js +49 -6
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +49 -6
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +2 -2
- package/dist/reviews/index.d.ts +2 -2
- package/dist/reviews/index.js +73 -8
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +73 -8
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/{transport-BGW9uXZJ.d.mts → transport-CF_eHwzC.d.mts} +15 -1
- package/dist/{transport-jUJd5kxu.d.ts → transport-DsRe4epC.d.ts} +15 -1
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/activation/useWireActivation.ts +12 -1
- package/src/activation/wireActivation.ts +36 -24
- package/src/analytics/analyticsFacade.ts +41 -20
- package/src/analytics/currentSession.ts +83 -0
- package/src/analytics/eventQueue.ts +9 -1
- package/src/analytics/index.ts +20 -1
- package/src/analytics/reportClientEvent.ts +38 -0
- package/src/analytics/screenTracking.ts +6 -1
- package/src/analytics/useAnalytics.ts +22 -1
- package/src/context/deviceId.ts +109 -0
- package/src/context/userContext.ts +18 -0
- package/src/index.ts +45 -1
- package/src/questionnaire/runtime.ts +12 -2
- package/src/questionnaire/useQuestionnaireGate.ts +9 -7
- package/src/revenuecat/index.ts +55 -0
- package/src/revenuecat/purchaseEvents.ts +167 -0
- package/src/revenuecat/revenueCatBridge.ts +221 -0
- package/src/revenuecat/types.ts +95 -0
- package/src/reviews/runtime.ts +92 -1
- package/src/reviews/transport.ts +21 -2
- package/src/reviews/useReviewGate.ts +12 -7
- package/src/session-analytics/lifecycle.ts +9 -2
- package/src/session-analytics/reportSessionStart.ts +15 -4
- package/src/session-analytics/useLifecycleEvents.ts +28 -2
package/dist/analytics/index.mjs
CHANGED
|
@@ -411,6 +411,23 @@ var buildEventsRequest = (target, events) => {
|
|
|
411
411
|
return null;
|
|
412
412
|
}
|
|
413
413
|
};
|
|
414
|
+
var warnOnSkippedEvents = (res) => {
|
|
415
|
+
try {
|
|
416
|
+
const json = res == null ? void 0 : res.json;
|
|
417
|
+
if (typeof json !== "function") return;
|
|
418
|
+
void Promise.resolve(json.call(res)).then((body) => {
|
|
419
|
+
const skipped = body == null ? void 0 : body.skipped;
|
|
420
|
+
if (typeof skipped !== "number" || skipped <= 0) return;
|
|
421
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
422
|
+
console.warn(
|
|
423
|
+
`[wireai] the server ACCEPTED the /v1/events POST but DISCARDED ${skipped} event(s) (skipped in the response body) \u2014 they are gone, not retried. The usual cause is an event with a missing or empty session_id.`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}).catch(() => {
|
|
427
|
+
});
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
430
|
+
};
|
|
414
431
|
var reportClientEvents = (target, events) => {
|
|
415
432
|
try {
|
|
416
433
|
const req = buildEventsRequest(target, events);
|
|
@@ -433,15 +450,54 @@ var reportClientEventsAwait = async (target, events) => {
|
|
|
433
450
|
};
|
|
434
451
|
var reportClientEventAwait = (target, event) => reportClientEventsAwait(target, [event]);
|
|
435
452
|
|
|
453
|
+
// src/analytics/currentSession.ts
|
|
454
|
+
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
455
|
+
"@wireai/activation:currentSessionId"
|
|
456
|
+
);
|
|
457
|
+
var globalSlot = globalThis;
|
|
458
|
+
var setCurrentSessionId = (id) => {
|
|
459
|
+
if (typeof id === "string" && id.length > 0) {
|
|
460
|
+
globalSlot[CURRENT_SESSION_ID_SLOT] = id;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
464
|
+
var resetCurrentSessionId = () => {
|
|
465
|
+
globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
|
|
466
|
+
};
|
|
467
|
+
var warnInDev = (message) => {
|
|
468
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
469
|
+
console.warn(message);
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
};
|
|
474
|
+
var MINT_WARNING = "[wireai] No app-open session was registered, so a session id was minted for this event (the server drops an event that has no session_id, and still answers 200). Mount useLifecycleEvents at your app root so events correlate to a real app-open.";
|
|
475
|
+
var MINT_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
|
|
476
|
+
"@wireai/activation:currentSessionIdMintWarned"
|
|
477
|
+
);
|
|
478
|
+
var warnSlot = globalThis;
|
|
479
|
+
var ensureCurrentSessionId = () => {
|
|
480
|
+
const existing = globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
481
|
+
if (typeof existing === "string" && existing.length > 0) return existing;
|
|
482
|
+
const minted = makeSessionId();
|
|
483
|
+
globalSlot[CURRENT_SESSION_ID_SLOT] = minted;
|
|
484
|
+
if (!warnSlot[MINT_WARNED_SLOT] && warnInDev(MINT_WARNING)) {
|
|
485
|
+
warnSlot[MINT_WARNED_SLOT] = true;
|
|
486
|
+
}
|
|
487
|
+
return minted;
|
|
488
|
+
};
|
|
489
|
+
|
|
436
490
|
// src/reviews/transport.ts
|
|
437
491
|
var reportAppEvent = (target, name2, options = {}) => {
|
|
492
|
+
var _a2;
|
|
438
493
|
if (!(target == null ? void 0 : target.serverUrl) || !name2) return;
|
|
439
494
|
try {
|
|
495
|
+
const supplied = (_a2 = options.sessionId) != null ? _a2 : "";
|
|
440
496
|
const event = {
|
|
441
497
|
event_type: "app_event",
|
|
442
|
-
question_key: name2
|
|
498
|
+
question_key: name2,
|
|
499
|
+
session_id: supplied.trim().length > 0 ? supplied : ensureCurrentSessionId()
|
|
443
500
|
};
|
|
444
|
-
if (options.sessionId) event.session_id = options.sessionId;
|
|
445
501
|
if (options.deviceKey) event.user_context = { device_key: options.deviceKey };
|
|
446
502
|
if (options.meta && Object.keys(options.meta).length > 0) {
|
|
447
503
|
event.meta = JSON.stringify(options.meta);
|
|
@@ -877,6 +933,7 @@ var createEventQueue = (options) => {
|
|
|
877
933
|
const timer = setTimeout(() => controller == null ? void 0 : controller.abort(), 15e3);
|
|
878
934
|
try {
|
|
879
935
|
const res = await fetch(req.url, { ...req.init, signal: controller == null ? void 0 : controller.signal });
|
|
936
|
+
warnOnSkippedEvents(res);
|
|
880
937
|
return !!(res && res.ok);
|
|
881
938
|
} catch {
|
|
882
939
|
return false;
|
|
@@ -955,21 +1012,6 @@ var createEventQueue = (options) => {
|
|
|
955
1012
|
return { enqueue, flush, notifyOnline, size };
|
|
956
1013
|
};
|
|
957
1014
|
|
|
958
|
-
// src/analytics/currentSession.ts
|
|
959
|
-
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
960
|
-
"@wireai/activation:currentSessionId"
|
|
961
|
-
);
|
|
962
|
-
var globalSlot = globalThis;
|
|
963
|
-
var setCurrentSessionId = (id) => {
|
|
964
|
-
if (typeof id === "string" && id.length > 0) {
|
|
965
|
-
globalSlot[CURRENT_SESSION_ID_SLOT] = id;
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
969
|
-
var resetCurrentSessionId = () => {
|
|
970
|
-
globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
|
|
971
|
-
};
|
|
972
|
-
|
|
973
1015
|
// src/identity/userIdentity.ts
|
|
974
1016
|
var USER_ID_MAX_LENGTH = 128;
|
|
975
1017
|
var sanitizeUserId = (raw) => {
|
|
@@ -1066,9 +1108,50 @@ var mintDeviceId = () => {
|
|
|
1066
1108
|
const time = Date.now().toString(36);
|
|
1067
1109
|
return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
|
|
1068
1110
|
};
|
|
1111
|
+
var AUTO_DEVICE_KEY_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:autoDeviceKeys");
|
|
1112
|
+
var deviceKeyGlobal = globalThis;
|
|
1113
|
+
var autoDeviceKeyRegistry = () => {
|
|
1114
|
+
const existing = deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT];
|
|
1115
|
+
if (existing) return existing;
|
|
1116
|
+
const created = { keys: /* @__PURE__ */ new Map(), hydrating: /* @__PURE__ */ new Set() };
|
|
1117
|
+
deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT] = created;
|
|
1118
|
+
return created;
|
|
1119
|
+
};
|
|
1120
|
+
var resolveAutoDeviceKey = (opts = {}) => {
|
|
1121
|
+
var _a2, _b;
|
|
1122
|
+
const registry = autoDeviceKeyRegistry();
|
|
1123
|
+
const appId = (_a2 = opts.appId) != null ? _a2 : "default";
|
|
1124
|
+
let id = registry.keys.get(appId);
|
|
1125
|
+
if (!id) {
|
|
1126
|
+
id = mintDeviceId();
|
|
1127
|
+
registry.keys.set(appId, id);
|
|
1128
|
+
}
|
|
1129
|
+
const storage = opts.storage;
|
|
1130
|
+
if (storage && !registry.hydrating.has(appId)) {
|
|
1131
|
+
registry.hydrating.add(appId);
|
|
1132
|
+
const slot = deviceIdStorageKey(appId);
|
|
1133
|
+
const minted = id;
|
|
1134
|
+
try {
|
|
1135
|
+
void Promise.resolve(storage.getItem(slot)).then((saved) => {
|
|
1136
|
+
const persisted = typeof saved === "string" && saved.trim() ? saved.trim() : void 0;
|
|
1137
|
+
if (persisted) registry.keys.set(appId, persisted);
|
|
1138
|
+
else void Promise.resolve(storage.setItem(slot, minted)).catch(() => {
|
|
1139
|
+
});
|
|
1140
|
+
}).catch(() => {
|
|
1141
|
+
});
|
|
1142
|
+
} catch {
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return (_b = registry.keys.get(appId)) != null ? _b : id;
|
|
1146
|
+
};
|
|
1147
|
+
var resetAutoDeviceKeys = () => {
|
|
1148
|
+
const registry = autoDeviceKeyRegistry();
|
|
1149
|
+
registry.keys.clear();
|
|
1150
|
+
registry.hydrating.clear();
|
|
1151
|
+
};
|
|
1069
1152
|
|
|
1070
1153
|
// src/analytics/analyticsFacade.ts
|
|
1071
|
-
var
|
|
1154
|
+
var warnInDev2 = (message) => {
|
|
1072
1155
|
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
1073
1156
|
console.warn(message);
|
|
1074
1157
|
}
|
|
@@ -1080,20 +1163,20 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1080
1163
|
var _a3, _b2;
|
|
1081
1164
|
return (_b2 = (_a3 = config.sessionId) != null ? _a3 : getCurrentSessionId()) != null ? _b2 : instanceSessionId;
|
|
1082
1165
|
};
|
|
1166
|
+
if (config.sessionId) {
|
|
1167
|
+
warnInDev2(
|
|
1168
|
+
"[wireai] createAnalytics({ sessionId }) PINS every event from this instance to that one frozen id and opts out of the live per-open session (app.session_started) \u2014 lifecycle analytics collapse onto a single device-scoped id. Remove it unless your host runs its own session lifecycle."
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
const detectedAppVersion = detectAppVersion();
|
|
1083
1172
|
let userContext = { ...(_b = config.userContext) != null ? _b : {} };
|
|
1084
1173
|
const hostDeviceKeyAtInit = typeof ((_c = config.userContext) == null ? void 0 : _c.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
if (persisted) autoDeviceKey = persisted;
|
|
1092
|
-
else void storage.setItem(deviceKey, autoDeviceKey).catch(() => {
|
|
1093
|
-
});
|
|
1094
|
-
}).catch(() => {
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1174
|
+
const autoDeviceKeyOptions = {
|
|
1175
|
+
appId: config.appId,
|
|
1176
|
+
// A host-supplied deviceKey opts out of minting AND persisting (unchanged contract).
|
|
1177
|
+
storage: hostDeviceKeyAtInit ? void 0 : config.storage
|
|
1178
|
+
};
|
|
1179
|
+
if (!hostDeviceKeyAtInit) resolveAutoDeviceKey(autoDeviceKeyOptions);
|
|
1097
1180
|
const envelope = () => {
|
|
1098
1181
|
var _a3;
|
|
1099
1182
|
return buildContextEnvelope({
|
|
@@ -1119,20 +1202,21 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1119
1202
|
});
|
|
1120
1203
|
}
|
|
1121
1204
|
const applyContext = (event) => {
|
|
1122
|
-
var _a3;
|
|
1205
|
+
var _a3, _b2;
|
|
1123
1206
|
const hostDeviceKey = typeof userContext.deviceKey === "string" && userContext.deviceKey.trim() ? userContext.deviceKey : void 0;
|
|
1124
1207
|
const resolved = resolveUserContext(
|
|
1125
|
-
|
|
1126
|
-
{
|
|
1208
|
+
// `??` is lazy on purpose: a host-supplied key must never even touch the auto registry.
|
|
1209
|
+
{ ...userContext, deviceKey: hostDeviceKey != null ? hostDeviceKey : resolveAutoDeviceKey(autoDeviceKeyOptions) },
|
|
1210
|
+
{ autoAppVersion: (_a3 = config.appVersion) != null ? _a3 : detectedAppVersion }
|
|
1127
1211
|
);
|
|
1128
1212
|
if (resolved.userContext) {
|
|
1129
|
-
event.user_context = { ...resolved.userContext, ...(
|
|
1213
|
+
event.user_context = { ...resolved.userContext, ...(_b2 = event.user_context) != null ? _b2 : {} };
|
|
1130
1214
|
}
|
|
1131
1215
|
if (boundUserId && !event.user_id) event.user_id = boundUserId;
|
|
1132
1216
|
};
|
|
1133
1217
|
const guardUserId = (clean) => {
|
|
1134
1218
|
if (config.allowEmailAsUserId || !looksLikeEmail(clean)) return clean;
|
|
1135
|
-
|
|
1219
|
+
warnInDev2(
|
|
1136
1220
|
"[wireai] identify() was called with an email-shaped id. A raw email must NOT be the opaque user_id (PII leak) \u2014 pass it as userContext.userEmail instead. Binding was skipped. Set allowEmailAsUserId:true on createAnalytics if your user id genuinely is an email."
|
|
1137
1221
|
);
|
|
1138
1222
|
return void 0;
|
|
@@ -1215,6 +1299,7 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1215
1299
|
};
|
|
1216
1300
|
};
|
|
1217
1301
|
var useAnalytics = (config, options = {}) => {
|
|
1302
|
+
var _a2;
|
|
1218
1303
|
const ref = useRef(void 0);
|
|
1219
1304
|
const prevKeys = useRef("");
|
|
1220
1305
|
const currentKeys = `${config.serverUrl}|${config.apiKey}|${config.appId}`;
|
|
@@ -1222,9 +1307,14 @@ var useAnalytics = (config, options = {}) => {
|
|
|
1222
1307
|
prevKeys.current = currentKeys;
|
|
1223
1308
|
ref.current = createAnalytics(config, options);
|
|
1224
1309
|
}
|
|
1310
|
+
const hostDeviceKey = typeof ((_a2 = config.userContext) == null ? void 0 : _a2.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
|
|
1311
|
+
useEffect(() => {
|
|
1312
|
+
var _a3;
|
|
1313
|
+
if (hostDeviceKey) (_a3 = ref.current) == null ? void 0 : _a3.setUserContext({ deviceKey: hostDeviceKey });
|
|
1314
|
+
}, [hostDeviceKey]);
|
|
1225
1315
|
return ref.current;
|
|
1226
1316
|
};
|
|
1227
1317
|
|
|
1228
|
-
export { WIRE_ONBOARDING_EVENTS, analyticsUserIdStorageKey, buildContextEnvelope, clearPiiFromContext, clearUserContext, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, getCurrentSessionId, looksLikeEmail, makeSessionId, reportAppEvent, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, resetCurrentSessionId, screenTrackingHandler, setCurrentSessionId, toAnalyticsEvent, useAnalytics, useScreenTracking };
|
|
1318
|
+
export { AUTO_DEVICE_ID_PREFIX, WIRE_ONBOARDING_EVENTS, analyticsUserIdStorageKey, buildContextEnvelope, clearPiiFromContext, clearUserContext, createAnalytics, createEventQueue, createScreenTracker, deviceIdStorageKey, ensureCurrentSessionId, getActiveRouteName, getCurrentSessionId, looksLikeEmail, makeSessionId, reportAppEvent, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, resetAutoDeviceKeys, resetCurrentSessionId, resolveAutoDeviceKey, screenTrackingHandler, setCurrentSessionId, toAnalyticsEvent, useAnalytics, useScreenTracking };
|
|
1229
1319
|
//# sourceMappingURL=index.mjs.map
|
|
1230
1320
|
//# sourceMappingURL=index.mjs.map
|