@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.
- package/AGENTS.md +51 -0
- package/CHANGELOG.md +111 -1
- package/INTEGRATION_PROMPT.md +13 -1
- package/README.md +106 -4
- package/dist/analytics/index.d.mts +35 -6
- package/dist/analytics/index.d.ts +35 -6
- package/dist/analytics/index.js +222 -94
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +214 -95
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/{currentSession-D0Vq7_VE.d.ts → currentSession-D6RiVtc8.d.ts} +187 -29
- package/dist/{currentSession-DdDkprpM.d.mts → currentSession-DsSDHqor.d.mts} +187 -29
- package/dist/index.d.mts +236 -82
- package/dist/index.d.ts +236 -82
- package/dist/index.js +330 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +314 -61
- 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 +59 -8
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +59 -8
- 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 +97 -17
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +97 -17
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/{transport-Bzb-bcB2.d.mts → transport-CF_eHwzC.d.mts} +15 -16
- package/dist/{transport-B31G0Cib.d.ts → transport-DsRe4epC.d.ts} +15 -16
- package/llms.txt +9 -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 +113 -29
- package/src/analytics/currentSession.ts +83 -0
- package/src/analytics/eventQueue.ts +20 -11
- package/src/analytics/index.ts +29 -1
- package/src/analytics/reportClientEvent.ts +50 -2
- 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 +73 -0
- package/src/identity/userIdentity.ts +10 -0
- package/src/index.ts +50 -2
- package/src/questionnaire/runtime.ts +12 -2
- package/src/questionnaire/transport.ts +5 -1
- 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/decision.ts +8 -1
- package/src/reviews/runtime.ts +92 -1
- package/src/reviews/transport.ts +27 -10
- package/src/reviews/useReviewGate.ts +12 -7
- package/src/session-analytics/lifecycle.ts +15 -13
- package/src/session-analytics/reportSessionStart.ts +15 -4
- package/src/session-analytics/useLifecycleEvents.ts +68 -28
package/dist/analytics/index.mjs
CHANGED
|
@@ -398,27 +398,113 @@ var init_Constants = __esm({
|
|
|
398
398
|
}
|
|
399
399
|
});
|
|
400
400
|
|
|
401
|
-
// src/
|
|
402
|
-
var
|
|
403
|
-
|
|
401
|
+
// src/analytics/reportClientEvent.ts
|
|
402
|
+
var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
403
|
+
var buildEventsRequest = (target, events) => {
|
|
404
|
+
if (!(target == null ? void 0 : target.serverUrl) || events.length === 0) return null;
|
|
404
405
|
try {
|
|
405
406
|
const url = `${target.serverUrl.replace(/\/$/, "")}/v1/events`;
|
|
406
407
|
const headers = { "Content-Type": "application/json" };
|
|
407
408
|
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
409
|
+
return { url, init: { method: "POST", headers, body: JSON.stringify({ events }) } };
|
|
410
|
+
} catch {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
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
|
+
};
|
|
431
|
+
var reportClientEvents = (target, events) => {
|
|
432
|
+
try {
|
|
433
|
+
const req = buildEventsRequest(target, events);
|
|
434
|
+
if (!req) return;
|
|
435
|
+
void fetch(req.url, req.init).catch(() => {
|
|
436
|
+
});
|
|
437
|
+
} catch {
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
var reportClientEvent = (target, event) => reportClientEvents(target, [event]);
|
|
441
|
+
var reportClientEventsAwait = async (target, events) => {
|
|
442
|
+
try {
|
|
443
|
+
const req = buildEventsRequest(target, events);
|
|
444
|
+
if (!req) return false;
|
|
445
|
+
const res = await fetch(req.url, req.init);
|
|
446
|
+
return Boolean(res && res.ok);
|
|
447
|
+
} catch {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
var reportClientEventAwait = (target, event) => reportClientEventsAwait(target, [event]);
|
|
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
|
+
|
|
490
|
+
// src/reviews/transport.ts
|
|
491
|
+
var reportAppEvent = (target, name2, options = {}) => {
|
|
492
|
+
var _a2;
|
|
493
|
+
if (!(target == null ? void 0 : target.serverUrl) || !name2) return;
|
|
494
|
+
try {
|
|
495
|
+
const supplied = (_a2 = options.sessionId) != null ? _a2 : "";
|
|
408
496
|
const event = {
|
|
409
497
|
event_type: "app_event",
|
|
410
|
-
question_key: name2
|
|
498
|
+
question_key: name2,
|
|
499
|
+
session_id: supplied.trim().length > 0 ? supplied : ensureCurrentSessionId()
|
|
411
500
|
};
|
|
412
|
-
if (options.sessionId) event.session_id = options.sessionId;
|
|
413
501
|
if (options.deviceKey) event.user_context = { device_key: options.deviceKey };
|
|
414
502
|
if (options.meta && Object.keys(options.meta).length > 0) {
|
|
415
503
|
event.meta = JSON.stringify(options.meta);
|
|
416
504
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
body: JSON.stringify({ events: [event] })
|
|
421
|
-
}).catch(() => {
|
|
505
|
+
const req = buildEventsRequest(target, [event]);
|
|
506
|
+
if (!req) return;
|
|
507
|
+
void fetch(req.url, req.init).catch(() => {
|
|
422
508
|
});
|
|
423
509
|
} catch {
|
|
424
510
|
}
|
|
@@ -495,41 +581,6 @@ var useScreenTracking = (navigationRef, options = {}) => {
|
|
|
495
581
|
}, [navigationRef]);
|
|
496
582
|
};
|
|
497
583
|
|
|
498
|
-
// src/analytics/reportClientEvent.ts
|
|
499
|
-
var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
500
|
-
var buildEventsRequest = (target, events) => {
|
|
501
|
-
if (!(target == null ? void 0 : target.serverUrl) || events.length === 0) return null;
|
|
502
|
-
try {
|
|
503
|
-
const url = `${target.serverUrl.replace(/\/$/, "")}/v1/events`;
|
|
504
|
-
const headers = { "Content-Type": "application/json" };
|
|
505
|
-
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
506
|
-
return { url, init: { method: "POST", headers, body: JSON.stringify({ events }) } };
|
|
507
|
-
} catch {
|
|
508
|
-
return null;
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
var reportClientEvents = (target, events) => {
|
|
512
|
-
try {
|
|
513
|
-
const req = buildEventsRequest(target, events);
|
|
514
|
-
if (!req) return;
|
|
515
|
-
void fetch(req.url, req.init).catch(() => {
|
|
516
|
-
});
|
|
517
|
-
} catch {
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
var reportClientEvent = (target, event) => reportClientEvents(target, [event]);
|
|
521
|
-
var reportClientEventsAwait = async (target, events) => {
|
|
522
|
-
try {
|
|
523
|
-
const req = buildEventsRequest(target, events);
|
|
524
|
-
if (!req) return false;
|
|
525
|
-
const res = await fetch(req.url, req.init);
|
|
526
|
-
return Boolean(res && res.ok);
|
|
527
|
-
} catch {
|
|
528
|
-
return false;
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
var reportClientEventAwait = (target, event) => reportClientEventsAwait(target, [event]);
|
|
532
|
-
|
|
533
584
|
// src/analytics/analyticsEvent.ts
|
|
534
585
|
var WIRE_ONBOARDING_EVENTS = {
|
|
535
586
|
started: "wire_onboarding_started",
|
|
@@ -820,6 +871,7 @@ var createEventQueue = (options) => {
|
|
|
820
871
|
var _a3;
|
|
821
872
|
const env = resolveEnvelope();
|
|
822
873
|
const stamped = { ...event };
|
|
874
|
+
if (stamped.ts === void 0) stamped.ts = Date.now();
|
|
823
875
|
if (!env) return stamped;
|
|
824
876
|
if (!stamped.device && env.device) stamped.device = env.device;
|
|
825
877
|
if (!stamped.session_id && env.sessionId) stamped.session_id = env.sessionId;
|
|
@@ -875,19 +927,13 @@ var createEventQueue = (options) => {
|
|
|
875
927
|
}
|
|
876
928
|
})();
|
|
877
929
|
const postBatch = async (events) => {
|
|
878
|
-
|
|
930
|
+
const req = buildEventsRequest(target, events);
|
|
931
|
+
if (!req) return false;
|
|
879
932
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
880
933
|
const timer = setTimeout(() => controller == null ? void 0 : controller.abort(), 15e3);
|
|
881
934
|
try {
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
885
|
-
const res = await fetch(url, {
|
|
886
|
-
method: "POST",
|
|
887
|
-
headers,
|
|
888
|
-
body: JSON.stringify({ events }),
|
|
889
|
-
signal: controller == null ? void 0 : controller.signal
|
|
890
|
-
});
|
|
935
|
+
const res = await fetch(req.url, { ...req.init, signal: controller == null ? void 0 : controller.signal });
|
|
936
|
+
warnOnSkippedEvents(res);
|
|
891
937
|
return !!(res && res.ok);
|
|
892
938
|
} catch {
|
|
893
939
|
return false;
|
|
@@ -966,21 +1012,6 @@ var createEventQueue = (options) => {
|
|
|
966
1012
|
return { enqueue, flush, notifyOnline, size };
|
|
967
1013
|
};
|
|
968
1014
|
|
|
969
|
-
// src/analytics/currentSession.ts
|
|
970
|
-
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
971
|
-
"@wireai/activation:currentSessionId"
|
|
972
|
-
);
|
|
973
|
-
var globalSlot = globalThis;
|
|
974
|
-
var setCurrentSessionId = (id) => {
|
|
975
|
-
if (typeof id === "string" && id.length > 0) {
|
|
976
|
-
globalSlot[CURRENT_SESSION_ID_SLOT] = id;
|
|
977
|
-
}
|
|
978
|
-
};
|
|
979
|
-
var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
980
|
-
var resetCurrentSessionId = () => {
|
|
981
|
-
globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
|
|
982
|
-
};
|
|
983
|
-
|
|
984
1015
|
// src/identity/userIdentity.ts
|
|
985
1016
|
var USER_ID_MAX_LENGTH = 128;
|
|
986
1017
|
var sanitizeUserId = (raw) => {
|
|
@@ -989,6 +1020,7 @@ var sanitizeUserId = (raw) => {
|
|
|
989
1020
|
if (!trimmed) return void 0;
|
|
990
1021
|
return trimmed.length > USER_ID_MAX_LENGTH ? trimmed.slice(0, USER_ID_MAX_LENGTH) : trimmed;
|
|
991
1022
|
};
|
|
1023
|
+
var looksLikeEmail = (value) => typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
|
|
992
1024
|
|
|
993
1025
|
// src/context/userContext.ts
|
|
994
1026
|
var EXTRA_KEY_PREFIX = "custom.";
|
|
@@ -1023,6 +1055,21 @@ var namespaceExtra = (extra) => {
|
|
|
1023
1055
|
}
|
|
1024
1056
|
return out;
|
|
1025
1057
|
};
|
|
1058
|
+
var analyticsUserIdStorageKey = (appId) => `wireai:analytics:userId:${appId != null ? appId : "default"}`;
|
|
1059
|
+
var clearPiiFromContext = (ctx = {}) => {
|
|
1060
|
+
const rest = {};
|
|
1061
|
+
if (typeof ctx.appVersion === "string") rest.appVersion = ctx.appVersion;
|
|
1062
|
+
if (typeof ctx.deviceKey === "string") rest.deviceKey = ctx.deviceKey;
|
|
1063
|
+
return rest;
|
|
1064
|
+
};
|
|
1065
|
+
var clearUserContext = async (opts = {}) => {
|
|
1066
|
+
const storage = opts.storage;
|
|
1067
|
+
if (!storage) return;
|
|
1068
|
+
try {
|
|
1069
|
+
await storage.removeItem(analyticsUserIdStorageKey(opts.appId));
|
|
1070
|
+
} catch {
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1026
1073
|
var resolveUserContext = (ctx = {}, opts = {}) => {
|
|
1027
1074
|
var _a2;
|
|
1028
1075
|
const result = {};
|
|
@@ -1061,29 +1108,75 @@ var mintDeviceId = () => {
|
|
|
1061
1108
|
const time = Date.now().toString(36);
|
|
1062
1109
|
return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
|
|
1063
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
|
+
};
|
|
1064
1152
|
|
|
1065
1153
|
// src/analytics/analyticsFacade.ts
|
|
1154
|
+
var warnInDev2 = (message) => {
|
|
1155
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
1156
|
+
console.warn(message);
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1066
1159
|
var createAnalytics = (config, options = {}) => {
|
|
1067
|
-
var _a2, _b, _c, _d
|
|
1160
|
+
var _a2, _b, _c, _d;
|
|
1068
1161
|
const instanceSessionId = (_a2 = config.sessionId) != null ? _a2 : makeSessionId();
|
|
1069
1162
|
const resolveSessionId = () => {
|
|
1070
1163
|
var _a3, _b2;
|
|
1071
1164
|
return (_b2 = (_a3 = config.sessionId) != null ? _a3 : getCurrentSessionId()) != null ? _b2 : instanceSessionId;
|
|
1072
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();
|
|
1073
1172
|
let userContext = { ...(_b = config.userContext) != null ? _b : {} };
|
|
1074
1173
|
const hostDeviceKeyAtInit = typeof ((_c = config.userContext) == null ? void 0 : _c.deviceKey) === "string" && config.userContext.deviceKey.trim() ? config.userContext.deviceKey.trim() : void 0;
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (persisted) autoDeviceKey = persisted;
|
|
1082
|
-
else void storage.setItem(deviceKey, autoDeviceKey).catch(() => {
|
|
1083
|
-
});
|
|
1084
|
-
}).catch(() => {
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
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);
|
|
1087
1180
|
const envelope = () => {
|
|
1088
1181
|
var _a3;
|
|
1089
1182
|
return buildContextEnvelope({
|
|
@@ -1101,7 +1194,7 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1101
1194
|
...options
|
|
1102
1195
|
});
|
|
1103
1196
|
let boundUserId = sanitizeUserId((_d = config.userContext) == null ? void 0 : _d.userId);
|
|
1104
|
-
const storageKey =
|
|
1197
|
+
const storageKey = analyticsUserIdStorageKey(config.appId);
|
|
1105
1198
|
if (config.storage) {
|
|
1106
1199
|
void config.storage.getItem(storageKey).then((saved) => {
|
|
1107
1200
|
if (saved && !boundUserId) boundUserId = saved;
|
|
@@ -1109,17 +1202,25 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1109
1202
|
});
|
|
1110
1203
|
}
|
|
1111
1204
|
const applyContext = (event) => {
|
|
1112
|
-
var _a3;
|
|
1205
|
+
var _a3, _b2;
|
|
1113
1206
|
const hostDeviceKey = typeof userContext.deviceKey === "string" && userContext.deviceKey.trim() ? userContext.deviceKey : void 0;
|
|
1114
1207
|
const resolved = resolveUserContext(
|
|
1115
|
-
|
|
1116
|
-
{
|
|
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 }
|
|
1117
1211
|
);
|
|
1118
1212
|
if (resolved.userContext) {
|
|
1119
|
-
event.user_context = { ...resolved.userContext, ...(
|
|
1213
|
+
event.user_context = { ...resolved.userContext, ...(_b2 = event.user_context) != null ? _b2 : {} };
|
|
1120
1214
|
}
|
|
1121
1215
|
if (boundUserId && !event.user_id) event.user_id = boundUserId;
|
|
1122
1216
|
};
|
|
1217
|
+
const guardUserId = (clean) => {
|
|
1218
|
+
if (config.allowEmailAsUserId || !looksLikeEmail(clean)) return clean;
|
|
1219
|
+
warnInDev2(
|
|
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."
|
|
1221
|
+
);
|
|
1222
|
+
return void 0;
|
|
1223
|
+
};
|
|
1123
1224
|
const setUserContext = (partial) => {
|
|
1124
1225
|
var _a3, _b2;
|
|
1125
1226
|
if (!partial || typeof partial !== "object") return;
|
|
@@ -1128,11 +1229,20 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1128
1229
|
if (mergedExtra) userContext.extra = mergedExtra;
|
|
1129
1230
|
const uid = sanitizeUserId(partial.userId);
|
|
1130
1231
|
if (uid) {
|
|
1131
|
-
|
|
1132
|
-
if (
|
|
1133
|
-
|
|
1232
|
+
const bindable = guardUserId(uid);
|
|
1233
|
+
if (bindable) {
|
|
1234
|
+
boundUserId = bindable;
|
|
1235
|
+
if (config.storage) void config.storage.setItem(storageKey, bindable).catch(() => {
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1134
1238
|
}
|
|
1135
1239
|
};
|
|
1240
|
+
const reset = () => {
|
|
1241
|
+
boundUserId = void 0;
|
|
1242
|
+
userContext = clearPiiFromContext(userContext);
|
|
1243
|
+
if (config.storage) void config.storage.removeItem(storageKey).catch(() => {
|
|
1244
|
+
});
|
|
1245
|
+
};
|
|
1136
1246
|
const track = (event, props) => {
|
|
1137
1247
|
if (!event) return;
|
|
1138
1248
|
const clientEvent = {
|
|
@@ -1159,9 +1269,11 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1159
1269
|
const identify = (userId, traits) => {
|
|
1160
1270
|
const clean = sanitizeUserId(userId);
|
|
1161
1271
|
if (!clean) return;
|
|
1162
|
-
|
|
1272
|
+
const bindable = guardUserId(clean);
|
|
1273
|
+
if (!bindable) return;
|
|
1274
|
+
boundUserId = bindable;
|
|
1163
1275
|
if (config.storage) {
|
|
1164
|
-
void config.storage.setItem(storageKey,
|
|
1276
|
+
void config.storage.setItem(storageKey, bindable).catch(() => {
|
|
1165
1277
|
});
|
|
1166
1278
|
}
|
|
1167
1279
|
const clientEvent = {
|
|
@@ -1169,7 +1281,7 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1169
1281
|
// Reuse the LIVE per-open session id (see `resolveSessionId`) so the server binds identity to
|
|
1170
1282
|
// the session it already saw instead of back-filling a phantom `session_started`.
|
|
1171
1283
|
session_id: resolveSessionId(),
|
|
1172
|
-
user_id:
|
|
1284
|
+
user_id: bindable
|
|
1173
1285
|
};
|
|
1174
1286
|
if (traits && Object.keys(traits).length > 0) clientEvent.meta = JSON.stringify(traits);
|
|
1175
1287
|
applyContext(clientEvent);
|
|
@@ -1180,12 +1292,14 @@ var createAnalytics = (config, options = {}) => {
|
|
|
1180
1292
|
screen,
|
|
1181
1293
|
identify,
|
|
1182
1294
|
setUserContext,
|
|
1295
|
+
reset,
|
|
1183
1296
|
flush: queue.flush,
|
|
1184
1297
|
notifyOnline: queue.notifyOnline,
|
|
1185
1298
|
size: queue.size
|
|
1186
1299
|
};
|
|
1187
1300
|
};
|
|
1188
1301
|
var useAnalytics = (config, options = {}) => {
|
|
1302
|
+
var _a2;
|
|
1189
1303
|
const ref = useRef(void 0);
|
|
1190
1304
|
const prevKeys = useRef("");
|
|
1191
1305
|
const currentKeys = `${config.serverUrl}|${config.apiKey}|${config.appId}`;
|
|
@@ -1193,9 +1307,14 @@ var useAnalytics = (config, options = {}) => {
|
|
|
1193
1307
|
prevKeys.current = currentKeys;
|
|
1194
1308
|
ref.current = createAnalytics(config, options);
|
|
1195
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]);
|
|
1196
1315
|
return ref.current;
|
|
1197
1316
|
};
|
|
1198
1317
|
|
|
1199
|
-
export { WIRE_ONBOARDING_EVENTS, buildContextEnvelope, createAnalytics, createEventQueue, createScreenTracker, getActiveRouteName, getCurrentSessionId, 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 };
|
|
1200
1319
|
//# sourceMappingURL=index.mjs.map
|
|
1201
1320
|
//# sourceMappingURL=index.mjs.map
|