@grafana/faro-react-native 1.3.1 → 1.4.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/README.md +176 -30
- package/android/build.gradle +17 -12
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashIds.kt +44 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +134 -38
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashSessionStore.kt +433 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +11 -2
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +128 -17
- package/android/src/main/java/com/grafana/faro/reactnative/FaroSessionProcess.kt +88 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FrameMonitor.kt +34 -42
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterBelowApi30Test.kt +21 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashReporterTest.kt +59 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashSessionStoreTest.kt +268 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroCrashTraceCacheTest.kt +52 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroSessionProcessTest.kt +127 -0
- package/dist/cjs/config/getRNInstrumentations.js +6 -8
- package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
- package/dist/cjs/config/sampling.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/dataCollection/DataCollectionPolicy.js +1 -2
- package/dist/cjs/dataCollection/DataCollectionPolicy.js.map +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
- package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/cjs/index.js +8 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/instrumentations/anr/instrumentation.js +10 -1
- package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/appState/index.js +8 -2
- package/dist/cjs/instrumentations/appState/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +19 -6
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +331 -0
- package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/cjs/instrumentations/errors/index.js +8 -3
- package/dist/cjs/instrumentations/errors/index.js.map +1 -1
- package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js +20 -31
- package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/frameMonitoring/types.js.map +1 -1
- package/dist/cjs/instrumentations/performance/index.js +2 -6
- package/dist/cjs/instrumentations/performance/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js +48 -0
- package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
- package/dist/cjs/instrumentations/session/directSessionActivity.js +37 -0
- package/dist/cjs/instrumentations/session/directSessionActivity.js.map +1 -0
- package/dist/cjs/instrumentations/session/index.js +214 -45
- package/dist/cjs/instrumentations/session/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionActivity.js +43 -0
- package/dist/cjs/instrumentations/session/sessionActivity.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionAttributes.js +8 -8
- package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +199 -24
- package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -13
- package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js +72 -0
- package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js +124 -96
- package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionManager/types.js.map +1 -1
- package/dist/cjs/instrumentations/session/sessionProcess.js +96 -0
- package/dist/cjs/instrumentations/session/sessionProcess.js.map +1 -0
- package/dist/cjs/instrumentations/startup/index.js +2 -6
- package/dist/cjs/instrumentations/startup/index.js.map +1 -1
- package/dist/cjs/navigation/utils.js +3 -1
- package/dist/cjs/navigation/utils.js.map +1 -1
- package/dist/cjs/transports/fetch/index.js.map +1 -1
- package/dist/cjs/transports/fetch/transport.js +56 -25
- package/dist/cjs/transports/fetch/transport.js.map +1 -1
- package/dist/cjs/transports/fetch/types.js.map +1 -1
- package/dist/cjs/transports/offline/ConnectivityService.js +1 -1
- package/dist/cjs/transports/offline/ConnectivityService.js.map +1 -1
- package/dist/cjs/transports/offline/OfflineCache.js +2 -2
- package/dist/cjs/transports/offline/OfflineCache.js.map +1 -1
- package/dist/cjs/transports/offline/transport.js +3 -4
- package/dist/cjs/transports/offline/transport.js.map +1 -1
- package/dist/cjs/userPersistence/UserPersistence.js +1 -2
- package/dist/cjs/userPersistence/UserPersistence.js.map +1 -1
- package/dist/esm/config/getRNInstrumentations.js +6 -8
- package/dist/esm/config/getRNInstrumentations.js.map +1 -1
- package/dist/esm/config/sampling.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/dataCollection/DataCollectionPolicy.js +1 -2
- package/dist/esm/dataCollection/DataCollectionPolicy.js.map +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js +1 -1
- package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instrumentations/anr/instrumentation.js +6 -1
- package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/appState/index.js +8 -2
- package/dist/esm/instrumentations/appState/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +15 -4
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +230 -0
- package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/esm/instrumentations/errors/index.js +8 -3
- package/dist/esm/instrumentations/errors/index.js.map +1 -1
- package/dist/esm/instrumentations/frameMonitoring/instrumentation.js +17 -32
- package/dist/esm/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/frameMonitoring/types.js.map +1 -1
- package/dist/esm/instrumentations/performance/index.js +2 -6
- package/dist/esm/instrumentations/performance/index.js.map +1 -1
- package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js +34 -0
- package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
- package/dist/esm/instrumentations/session/directSessionActivity.js +32 -0
- package/dist/esm/instrumentations/session/directSessionActivity.js.map +1 -0
- package/dist/esm/instrumentations/session/index.js +207 -46
- package/dist/esm/instrumentations/session/index.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionActivity.js +38 -0
- package/dist/esm/instrumentations/session/sessionActivity.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionAttributes.js +7 -7
- package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +190 -27
- package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -14
- package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js +56 -0
- package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js +1 -1
- package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js +120 -44
- package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionManager/types.js.map +1 -1
- package/dist/esm/instrumentations/session/sessionProcess.js +89 -0
- package/dist/esm/instrumentations/session/sessionProcess.js.map +1 -0
- package/dist/esm/instrumentations/startup/index.js +2 -6
- package/dist/esm/instrumentations/startup/index.js.map +1 -1
- package/dist/esm/navigation/utils.js +2 -1
- package/dist/esm/navigation/utils.js.map +1 -1
- package/dist/esm/transports/fetch/index.js.map +1 -1
- package/dist/esm/transports/fetch/transport.js +38 -14
- package/dist/esm/transports/fetch/transport.js.map +1 -1
- package/dist/esm/transports/fetch/types.js.map +1 -1
- package/dist/esm/transports/offline/ConnectivityService.js +1 -1
- package/dist/esm/transports/offline/ConnectivityService.js.map +1 -1
- package/dist/esm/transports/offline/OfflineCache.js +2 -2
- package/dist/esm/transports/offline/OfflineCache.js.map +1 -1
- package/dist/esm/transports/offline/transport.js +3 -4
- package/dist/esm/transports/offline/transport.js.map +1 -1
- package/dist/esm/userPersistence/UserPersistence.js +1 -2
- package/dist/esm/userPersistence/UserPersistence.js.map +1 -1
- package/dist/types/config/getRNInstrumentations.d.ts +1 -2
- package/dist/types/config/sampling.d.ts +0 -3
- package/dist/types/config/types.d.ts +5 -3
- package/dist/types/dataCollection/DataCollectionPolicy.d.ts +1 -2
- package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +14 -4
- package/dist/types/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.d.ts +27 -0
- package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +2 -2
- package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +2 -2
- package/dist/types/instrumentations/crashReporting/types.d.ts +6 -0
- package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +2 -2
- package/dist/types/instrumentations/frameMonitoring/types.d.ts +4 -6
- package/dist/types/instrumentations/performance/index.d.ts +0 -2
- package/dist/types/instrumentations/session/FaroSessionActivityBoundary.d.ts +8 -0
- package/dist/types/instrumentations/session/directSessionActivity.d.ts +13 -0
- package/dist/types/instrumentations/session/index.d.ts +20 -1
- package/dist/types/instrumentations/session/sessionActivity.d.ts +9 -0
- package/dist/types/instrumentations/session/sessionAttributes.d.ts +6 -3
- package/dist/types/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.d.ts +16 -3
- package/dist/types/instrumentations/session/sessionManager/VolatileSessionManager.d.ts +9 -3
- package/dist/types/instrumentations/session/sessionManager/persistentSessionRecord.d.ts +4 -0
- package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +19 -7
- package/dist/types/instrumentations/session/sessionManager/types.d.ts +6 -0
- package/dist/types/instrumentations/session/sessionProcess.d.ts +17 -0
- package/dist/types/instrumentations/startup/index.d.ts +2 -6
- package/dist/types/navigation/utils.d.ts +1 -0
- package/dist/types/transports/fetch/index.d.ts +1 -1
- package/dist/types/transports/fetch/transport.d.ts +8 -1
- package/dist/types/transports/fetch/types.d.ts +5 -0
- package/dist/types/transports/offline/ConnectivityService.d.ts +1 -1
- package/dist/types/transports/offline/OfflineCache.d.ts +2 -2
- package/dist/types/transports/offline/transport.d.ts +3 -4
- package/dist/types/userPersistence/UserPersistence.d.ts +1 -2
- package/ios/FaroCrashReporter.swift +214 -21
- package/ios/FaroReactNative.swift +24 -0
- package/ios/FaroReactNativeModule.h +2 -1
- package/ios/FaroReactNativeModule.mm +121 -6
- package/ios/RefreshRateVitals.swift +34 -38
- package/package.json +7 -5
- package/src/config/getRNInstrumentations.ts +6 -8
- package/src/config/makeRNConfig.test.ts +6 -0
- package/src/config/sampling.ts +0 -3
- package/src/config/types.ts +5 -3
- package/src/dataCollection/DataCollectionPolicy.ts +1 -2
- package/src/generated/faroRNPackageMeta.ts +1 -1
- package/src/index.ts +8 -2
- package/src/instrumentations/anr/instrumentation.ts +8 -1
- package/src/instrumentations/appState/index.ts +10 -2
- package/src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts +28 -8
- package/src/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.ts +277 -0
- package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +2 -2
- package/src/instrumentations/crashReporting/instrumentation.test.ts +433 -5
- package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +2 -2
- package/src/instrumentations/crashReporting/types.ts +7 -0
- package/src/instrumentations/errors/index.ts +12 -4
- package/src/instrumentations/errors/instrumentation.test.ts +35 -0
- package/src/instrumentations/frameMonitoring/instrumentation.test.ts +155 -0
- package/src/instrumentations/frameMonitoring/instrumentation.ts +19 -38
- package/src/instrumentations/frameMonitoring/types.ts +4 -6
- package/src/instrumentations/performance/index.ts +2 -6
- package/src/instrumentations/session/FaroSessionActivityBoundary.test.ts +60 -0
- package/src/instrumentations/session/FaroSessionActivityBoundary.tsx +41 -0
- package/src/instrumentations/session/beforeSendHook.test.ts +246 -0
- package/src/instrumentations/session/directSessionActivity.test.ts +158 -0
- package/src/instrumentations/session/directSessionActivity.ts +36 -0
- package/src/instrumentations/session/index.ts +269 -46
- package/src/instrumentations/session/persistentColdStart.test.ts +196 -0
- package/src/instrumentations/session/sessionActivity.test.ts +68 -0
- package/src/instrumentations/session/sessionActivity.ts +58 -0
- package/src/instrumentations/session/sessionAttributes.test.ts +37 -2
- package/src/instrumentations/session/sessionAttributes.ts +12 -6
- package/src/instrumentations/session/sessionCleanup.test.ts +410 -0
- package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.test.ts +552 -0
- package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts +249 -33
- package/src/instrumentations/session/sessionManager/VolatileSessionManager.ts +38 -18
- package/src/instrumentations/session/sessionManager/persistentSessionRecord.test.ts +103 -0
- package/src/instrumentations/session/sessionManager/persistentSessionRecord.ts +78 -0
- package/src/instrumentations/session/sessionManager/sampling.test.ts +1 -1
- package/src/instrumentations/session/sessionManager/sessionConstants.ts +1 -1
- package/src/instrumentations/session/sessionManager/sessionManagerUtils.test.ts +256 -18
- package/src/instrumentations/session/sessionManager/sessionManagerUtils.ts +180 -39
- package/src/instrumentations/session/sessionManager/types.ts +8 -0
- package/src/instrumentations/session/sessionManagerInstance.test.ts +65 -0
- package/src/instrumentations/session/sessionProcess.test.ts +136 -0
- package/src/instrumentations/session/sessionProcess.ts +114 -0
- package/src/instrumentations/session/startNewSession.test.ts +337 -0
- package/src/instrumentations/startup/index.ts +2 -6
- package/src/navigation/utils.ts +3 -1
- package/src/transports/fetch/index.ts +6 -1
- package/src/transports/fetch/transport.test.ts +86 -2
- package/src/transports/fetch/transport.ts +38 -16
- package/src/transports/fetch/types.ts +7 -0
- package/src/transports/offline/ConnectivityService.ts +1 -1
- package/src/transports/offline/OfflineCache.ts +2 -2
- package/src/transports/offline/transport.ts +3 -4
- package/src/userPersistence/UserPersistence.ts +1 -2
- package/dist/cjs/utils/throttle.js +0 -42
- package/dist/cjs/utils/throttle.js.map +0 -1
- package/dist/esm/utils/throttle.js +0 -34
- package/dist/esm/utils/throttle.js.map +0 -1
- package/dist/types/utils/throttle.d.ts +0 -9
- package/src/utils/throttle.test.ts +0 -141
- package/src/utils/throttle.ts +0 -34
|
@@ -27,11 +27,78 @@ var __assign = (this && this.__assign) || function () {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.SessionInstrumentation = void 0;
|
|
30
|
+
exports.startNewSession = startNewSession;
|
|
30
31
|
var faro_core_1 = require("@grafana/faro-core");
|
|
32
|
+
var directSessionActivity_1 = require("./directSessionActivity");
|
|
33
|
+
var sessionActivity_1 = require("./sessionActivity");
|
|
31
34
|
var sessionAttributes_1 = require("./sessionAttributes");
|
|
32
35
|
var sessionManager_1 = require("./sessionManager");
|
|
33
36
|
var sessionConstants_1 = require("./sessionManager/sessionConstants");
|
|
34
37
|
var sessionManagerUtils_1 = require("./sessionManager/sessionManagerUtils");
|
|
38
|
+
var SESSION_INSTRUMENTATION_NAME = '@grafana/faro-react-native:instrumentation-session';
|
|
39
|
+
// Track the current session hook per transport so superseded hooks yield to a
|
|
40
|
+
// replacement. The shared fallback preserves sampling decisions captured on
|
|
41
|
+
// queued items after the owning instrumentation has detached.
|
|
42
|
+
var activeSessionBeforeSendHooks = new WeakMap();
|
|
43
|
+
var sessionSamplingFallbackHooks = new WeakMap();
|
|
44
|
+
function applySessionSampling(item, fallbackSamplingDecision) {
|
|
45
|
+
var _a, _b, _c, _d;
|
|
46
|
+
var attributes = (_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.attributes;
|
|
47
|
+
var samplingAttribute = (_b = attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) !== null && _b !== void 0 ? _b : fallbackSamplingDecision === null || fallbackSamplingDecision === void 0 ? void 0 : fallbackSamplingDecision.toString();
|
|
48
|
+
if (samplingAttribute === 'false') {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
if (samplingAttribute !== 'true') {
|
|
52
|
+
return item;
|
|
53
|
+
}
|
|
54
|
+
var sampledItem = __assign(__assign({}, item), { meta: __assign(__assign({}, item.meta), { session: item.meta.session
|
|
55
|
+
? __assign(__assign({}, item.meta.session), { attributes: item.meta.session.attributes ? __assign({}, item.meta.session.attributes) : undefined }) : undefined }) });
|
|
56
|
+
var sampledAttributes = (_c = sampledItem.meta.session) === null || _c === void 0 ? void 0 : _c.attributes;
|
|
57
|
+
sampledAttributes === null || sampledAttributes === void 0 ? true : delete sampledAttributes['isSampled'];
|
|
58
|
+
if (Object.keys(sampledAttributes !== null && sampledAttributes !== void 0 ? sampledAttributes : {}).length === 0) {
|
|
59
|
+
(_d = sampledItem.meta.session) === null || _d === void 0 ? true : delete _d.attributes;
|
|
60
|
+
}
|
|
61
|
+
return sampledItem;
|
|
62
|
+
}
|
|
63
|
+
function ensureSessionSamplingFallback(transports) {
|
|
64
|
+
if (sessionSamplingFallbackHooks.has(transports)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
var fallbackHook = function (item) {
|
|
68
|
+
return activeSessionBeforeSendHooks.has(transports) ? item : applySessionSampling(item);
|
|
69
|
+
};
|
|
70
|
+
transports.addBeforeSendHooks(fallbackHook);
|
|
71
|
+
sessionSamplingFallbackHooks.set(transports, fallbackHook);
|
|
72
|
+
}
|
|
73
|
+
function removeInternalSamplingAttribute(session) {
|
|
74
|
+
var _a;
|
|
75
|
+
if (((_a = session === null || session === void 0 ? void 0 : session.attributes) === null || _a === void 0 ? void 0 : _a['isSampled']) == null) {
|
|
76
|
+
return session;
|
|
77
|
+
}
|
|
78
|
+
var attributes = __assign({}, session.attributes);
|
|
79
|
+
delete attributes['isSampled'];
|
|
80
|
+
return __assign(__assign({}, session), { attributes: Object.keys(attributes).length === 0 ? undefined : attributes });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Starts a new linked session at an application-defined boundary.
|
|
84
|
+
*
|
|
85
|
+
* Call this after changing or clearing the current user for logout, account
|
|
86
|
+
* changes, or another boundary that must not share a session. Calls made
|
|
87
|
+
* before Faro initializes, after teardown, or while session tracking is
|
|
88
|
+
* disabled have no effect.
|
|
89
|
+
*/
|
|
90
|
+
function startNewSession() {
|
|
91
|
+
var _a;
|
|
92
|
+
var instrumentation = (_a = faro_core_1.faro === null || faro_core_1.faro === void 0 ? void 0 : faro_core_1.faro.instrumentations) === null || _a === void 0 ? void 0 : _a.instrumentations.find(function (_a) {
|
|
93
|
+
var name = _a.name;
|
|
94
|
+
return name === SESSION_INSTRUMENTATION_NAME;
|
|
95
|
+
});
|
|
96
|
+
if (instrumentation != null &&
|
|
97
|
+
'startNewSession' in instrumentation &&
|
|
98
|
+
typeof instrumentation.startNewSession === 'function') {
|
|
99
|
+
instrumentation.startNewSession();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
35
102
|
/**
|
|
36
103
|
* Session instrumentation for React Native
|
|
37
104
|
* Manages persistent or volatile sessions with expiration and inactivity tracking
|
|
@@ -40,8 +107,19 @@ var SessionInstrumentation = /** @class */ (function (_super) {
|
|
|
40
107
|
__extends(SessionInstrumentation, _super);
|
|
41
108
|
function SessionInstrumentation() {
|
|
42
109
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
43
|
-
_this.name =
|
|
110
|
+
_this.name = SESSION_INSTRUMENTATION_NAME;
|
|
44
111
|
_this.version = faro_core_1.VERSION;
|
|
112
|
+
_this.isResettingSession = false;
|
|
113
|
+
_this.sendSessionStartEvent = function (meta) {
|
|
114
|
+
var _a;
|
|
115
|
+
var session = meta.session;
|
|
116
|
+
if (session && session.id !== ((_a = _this.notifiedSession) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
117
|
+
_this.notifiedSession = session;
|
|
118
|
+
// no need to add attributes and session id, they are included as part of meta
|
|
119
|
+
// automatically
|
|
120
|
+
_this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
|
|
121
|
+
}
|
|
122
|
+
};
|
|
45
123
|
return _this;
|
|
46
124
|
}
|
|
47
125
|
SessionInstrumentation.prototype.getDefaultSessionDeviceAttributes = function () {
|
|
@@ -51,24 +129,20 @@ var SessionInstrumentation = /** @class */ (function (_super) {
|
|
|
51
129
|
}
|
|
52
130
|
return (0, sessionAttributes_1.minimalSessionDeviceAttributes)();
|
|
53
131
|
};
|
|
54
|
-
SessionInstrumentation.prototype.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (session && session.id !== ((_a = this.notifiedSession) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
58
|
-
this.notifiedSession = session;
|
|
59
|
-
// no need to add attributes and session id, they are included as part of meta
|
|
60
|
-
// automatically
|
|
61
|
-
this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
|
|
62
|
-
}
|
|
132
|
+
SessionInstrumentation.prototype.registerSessionMetaListener = function () {
|
|
133
|
+
this.metas.addListener(this.sendSessionStartEvent);
|
|
134
|
+
this.sessionMetaListenerMetas = this.metas;
|
|
63
135
|
};
|
|
64
136
|
SessionInstrumentation.prototype.createInitialSession = function (SessionManagerClass, sessionsConfig) {
|
|
65
|
-
var _a, _b, _c, _d, _e, _f
|
|
137
|
+
var _a, _b, _c, _d, _e, _f;
|
|
66
138
|
var storedUserSession = SessionManagerClass.fetchUserSession();
|
|
67
139
|
var sessionsConfigTyped = sessionsConfig;
|
|
68
140
|
var maxPersistenceMs = (_a = sessionsConfigTyped.maxSessionPersistenceTime) !== null && _a !== void 0 ? _a : sessionConstants_1.MAX_SESSION_PERSISTENCE_TIME;
|
|
69
141
|
if (sessionsConfig.persistent && storedUserSession) {
|
|
70
142
|
var now = (0, faro_core_1.dateNow)();
|
|
71
|
-
var shouldClearPersistentSession = storedUserSession.
|
|
143
|
+
var shouldClearPersistentSession = storedUserSession.started > now ||
|
|
144
|
+
storedUserSession.lastActivity > now ||
|
|
145
|
+
storedUserSession.lastActivity <= now - maxPersistenceMs;
|
|
72
146
|
if (shouldClearPersistentSession) {
|
|
73
147
|
SessionManagerClass.removeUserSession();
|
|
74
148
|
storedUserSession = null;
|
|
@@ -77,7 +151,7 @@ var SessionInstrumentation = /** @class */ (function (_super) {
|
|
|
77
151
|
var defaultAttributes = this.getDefaultSessionDeviceAttributes();
|
|
78
152
|
var emitSessionStartOnInit;
|
|
79
153
|
var initialSession;
|
|
80
|
-
if ((0, sessionManagerUtils_1.isUserSessionValid)(storedUserSession)) {
|
|
154
|
+
if (!sessionsConfig.persistent && (0, sessionManagerUtils_1.isUserSessionValid)(storedUserSession)) {
|
|
81
155
|
var sessionId = storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId;
|
|
82
156
|
initialSession = (0, sessionManagerUtils_1.createUserSessionObject)({
|
|
83
157
|
sessionId: sessionId,
|
|
@@ -94,71 +168,166 @@ var SessionInstrumentation = /** @class */ (function (_super) {
|
|
|
94
168
|
emitSessionStartOnInit = false;
|
|
95
169
|
}
|
|
96
170
|
else {
|
|
97
|
-
var sessionId = (_e = (_d = sessionsConfig.session) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : (0, faro_core_1.genShortID)();
|
|
98
171
|
initialSession = (0, sessionManagerUtils_1.createUserSessionObject)({
|
|
99
|
-
sessionId:
|
|
172
|
+
sessionId: (_d = sessionsConfig.session) === null || _d === void 0 ? void 0 : _d.id,
|
|
100
173
|
isSampled: (0, sessionManager_1.isSampled)(),
|
|
101
174
|
});
|
|
102
|
-
var
|
|
103
|
-
|
|
175
|
+
var sessionId = initialSession.sessionId;
|
|
176
|
+
var previousSessionId = (storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId) === sessionId ? undefined : storedUserSession === null || storedUserSession === void 0 ? void 0 : storedUserSession.sessionId;
|
|
177
|
+
var overrides = (_e = sessionsConfig.session) === null || _e === void 0 ? void 0 : _e.overrides;
|
|
178
|
+
initialSession.sessionMeta = __assign({ id: sessionId, attributes: __assign(__assign(__assign(__assign({}, (_f = sessionsConfig.session) === null || _f === void 0 ? void 0 : _f.attributes), defaultAttributes), { isSampled: initialSession.isSampled.toString() }), (previousSessionId == null ? {} : { previousSession: previousSessionId })) }, (overrides ? { overrides: overrides } : {}));
|
|
104
179
|
emitSessionStartOnInit = true;
|
|
105
180
|
}
|
|
106
181
|
return { initialSession: initialSession, emitSessionStartOnInit: emitSessionStartOnInit };
|
|
107
182
|
};
|
|
108
183
|
SessionInstrumentation.prototype.registerBeforeSendHook = function (SessionManagerClass) {
|
|
109
|
-
var
|
|
110
|
-
var
|
|
111
|
-
(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// If no isSampled attribute, pass through the item unchanged
|
|
118
|
-
if ((attributes === null || attributes === void 0 ? void 0 : attributes['isSampled']) === 'false') {
|
|
119
|
-
// Session is not sampled - drop this item
|
|
120
|
-
return null;
|
|
184
|
+
var _this = this;
|
|
185
|
+
var registeredTransports = this.transports;
|
|
186
|
+
ensureSessionSamplingFallback(registeredTransports);
|
|
187
|
+
var beforeSendHook = function (item) {
|
|
188
|
+
var _a;
|
|
189
|
+
var activeBeforeSendHook = activeSessionBeforeSendHooks.get(registeredTransports);
|
|
190
|
+
if (activeBeforeSendHook != null && activeBeforeSendHook !== beforeSendHook) {
|
|
191
|
+
return item;
|
|
121
192
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
193
|
+
var nextItem = item;
|
|
194
|
+
var fallbackSamplingDecision;
|
|
195
|
+
var sessionManager = _this.beforeSendHook === beforeSendHook ? _this.sessionManagerInstance : undefined;
|
|
196
|
+
if (sessionManager != null) {
|
|
197
|
+
var storedSession = SessionManagerClass.fetchUserSession();
|
|
198
|
+
var recoveredCrash = (0, sessionActivity_1.isRecoveredCrashItem)(item, storedSession === null || storedSession === void 0 ? void 0 : storedSession.sessionId);
|
|
199
|
+
// Ending an active action can send telemetry synchronously. Keep that
|
|
200
|
+
// telemetry on the current session until the explicit reset completes.
|
|
201
|
+
var checkedSession = recoveredCrash
|
|
202
|
+
? null
|
|
203
|
+
: _this.isResettingSession
|
|
204
|
+
? storedSession
|
|
205
|
+
: sessionManager.checkSession((0, sessionActivity_1.classifySessionActivity)(item), storedSession);
|
|
206
|
+
if ((checkedSession === null || checkedSession === void 0 ? void 0 : checkedSession.sessionMeta) != null && ((_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.id) !== checkedSession.sessionId) {
|
|
207
|
+
nextItem = __assign(__assign({}, item), { meta: __assign(__assign({}, item.meta), { session: checkedSession.sessionMeta }) });
|
|
129
208
|
}
|
|
130
|
-
|
|
209
|
+
// New crash records carry the crash-time decision. Older records may not,
|
|
210
|
+
// so retain the previous behavior and use the live session's stable
|
|
211
|
+
// decision rather than implicitly sampling every recovered crash.
|
|
212
|
+
fallbackSamplingDecision = recoveredCrash ? storedSession === null || storedSession === void 0 ? void 0 : storedSession.isSampled : checkedSession === null || checkedSession === void 0 ? void 0 : checkedSession.isSampled;
|
|
131
213
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
214
|
+
return applySessionSampling(nextItem, fallbackSamplingDecision);
|
|
215
|
+
};
|
|
216
|
+
this.beforeSendHook = beforeSendHook;
|
|
217
|
+
this.beforeSendHookApi = this.api;
|
|
218
|
+
this.beforeSendHookTransports = registeredTransports;
|
|
219
|
+
registeredTransports.addBeforeSendHooks(beforeSendHook);
|
|
220
|
+
activeSessionBeforeSendHooks.set(registeredTransports, beforeSendHook);
|
|
135
221
|
};
|
|
136
222
|
SessionInstrumentation.prototype.initialize = function () {
|
|
223
|
+
var _this = this;
|
|
224
|
+
// BaseInstrumentation instances can be registered more than once. Detach
|
|
225
|
+
// every resource from the previous Faro instance before binding the next.
|
|
226
|
+
this.unpatch();
|
|
137
227
|
var sessionTrackingConfig = this.config.sessionTracking;
|
|
228
|
+
// A new initialization owns direct-activity routing, including when
|
|
229
|
+
// session tracking is disabled.
|
|
230
|
+
(0, directSessionActivity_1.clearDirectSessionActivityHandler)();
|
|
138
231
|
if (!(sessionTrackingConfig === null || sessionTrackingConfig === void 0 ? void 0 : sessionTrackingConfig.enabled)) {
|
|
139
|
-
this.
|
|
232
|
+
this.registerSessionMetaListener();
|
|
140
233
|
return;
|
|
141
234
|
}
|
|
142
235
|
var SessionManagerClass = (0, sessionManager_1.getSessionManagerByConfig)(sessionTrackingConfig);
|
|
236
|
+
// Constructing a manager registers an AppState subscription and a metas
|
|
237
|
+
// listener, so exactly one instance is created and reused. It is also the
|
|
238
|
+
// instance `unpatch()` cleans up.
|
|
239
|
+
this.sessionManagerInstance = new SessionManagerClass(this.metas);
|
|
143
240
|
this.registerBeforeSendHook(SessionManagerClass);
|
|
144
241
|
var _a = this.createInitialSession(SessionManagerClass, sessionTrackingConfig), initialSession = _a.initialSession, emitSessionStartOnInit = _a.emitSessionStartOnInit;
|
|
145
242
|
SessionManagerClass.storeUserSession(initialSession);
|
|
146
243
|
var initialSessionMeta = initialSession.sessionMeta;
|
|
147
244
|
this.notifiedSession = initialSessionMeta;
|
|
148
245
|
this.api.setSession(initialSessionMeta);
|
|
149
|
-
this.sessionManagerInstance = new SessionManagerClass();
|
|
150
246
|
if (emitSessionStartOnInit) {
|
|
151
247
|
this.api.pushEvent(faro_core_1.EVENT_SESSION_START, {}, undefined, { skipDedupe: true });
|
|
152
248
|
}
|
|
153
|
-
this.
|
|
249
|
+
this.unregisterDirectSessionActivity = (0, directSessionActivity_1.registerDirectSessionActivityHandler)(function () {
|
|
250
|
+
var _a;
|
|
251
|
+
(_a = _this.sessionManagerInstance) === null || _a === void 0 ? void 0 : _a.checkSession(sessionActivity_1.SessionActivityKind.Meaningful);
|
|
252
|
+
});
|
|
253
|
+
this.registerSessionMetaListener();
|
|
254
|
+
};
|
|
255
|
+
/** Starts a new linked session immediately. */
|
|
256
|
+
SessionInstrumentation.prototype.startNewSession = function () {
|
|
257
|
+
var _a, _b;
|
|
258
|
+
if (this.sessionManagerInstance == null || this.isResettingSession) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
this.isResettingSession = true;
|
|
262
|
+
try {
|
|
263
|
+
try {
|
|
264
|
+
var activeAction = (_b = (_a = this.api).getActiveUserAction) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
265
|
+
activeAction === null || activeAction === void 0 ? void 0 : activeAction.end();
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
this.logWarn('Failed to end the active user action before resetting the session:', error);
|
|
269
|
+
}
|
|
270
|
+
this.sessionManagerInstance.resetSession();
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
this.isResettingSession = false;
|
|
274
|
+
}
|
|
154
275
|
};
|
|
155
276
|
/**
|
|
156
277
|
* Clean up session manager listeners
|
|
157
278
|
*/
|
|
158
279
|
SessionInstrumentation.prototype.unpatch = function () {
|
|
159
|
-
|
|
160
|
-
|
|
280
|
+
var _a, _b;
|
|
281
|
+
(_a = this.unregisterDirectSessionActivity) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
282
|
+
this.unregisterDirectSessionActivity = undefined;
|
|
283
|
+
var beforeSendHook = this.beforeSendHook;
|
|
284
|
+
var beforeSendHookApi = this.beforeSendHookApi;
|
|
285
|
+
var beforeSendHookTransports = this.beforeSendHookTransports;
|
|
286
|
+
var ownedActiveHook = beforeSendHook != null &&
|
|
287
|
+
beforeSendHookTransports != null &&
|
|
288
|
+
activeSessionBeforeSendHooks.get(beforeSendHookTransports) === beforeSendHook;
|
|
289
|
+
// Stop the manager's metas synchronization before removing the internal
|
|
290
|
+
// sampling marker. Keep the session hook active during that update so any
|
|
291
|
+
// surviving metas listener that emits telemetry is still attributed and
|
|
292
|
+
// filtered with the current session.
|
|
293
|
+
(_b = this.sessionManagerInstance) === null || _b === void 0 ? void 0 : _b.unpatch();
|
|
294
|
+
try {
|
|
295
|
+
if (ownedActiveHook && beforeSendHookApi) {
|
|
296
|
+
var session = beforeSendHookApi.getSession();
|
|
297
|
+
var sessionWithoutSamplingAttribute = removeInternalSamplingAttribute(session);
|
|
298
|
+
if (sessionWithoutSamplingAttribute !== session) {
|
|
299
|
+
this.isResettingSession = true;
|
|
300
|
+
try {
|
|
301
|
+
beforeSendHookApi.setSession(sessionWithoutSamplingAttribute);
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
this.isResettingSession = false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
161
308
|
}
|
|
309
|
+
finally {
|
|
310
|
+
this.beforeSendHook = undefined;
|
|
311
|
+
this.beforeSendHookApi = undefined;
|
|
312
|
+
this.beforeSendHookTransports = undefined;
|
|
313
|
+
if (beforeSendHook && beforeSendHookTransports) {
|
|
314
|
+
if (ownedActiveHook) {
|
|
315
|
+
activeSessionBeforeSendHooks.delete(beforeSendHookTransports);
|
|
316
|
+
}
|
|
317
|
+
beforeSendHookTransports.removeBeforeSendHooks(beforeSendHook);
|
|
318
|
+
}
|
|
319
|
+
this.sessionManagerInstance = undefined;
|
|
320
|
+
var sessionMetaListenerMetas = this.sessionMetaListenerMetas;
|
|
321
|
+
this.sessionMetaListenerMetas = undefined;
|
|
322
|
+
if (sessionMetaListenerMetas) {
|
|
323
|
+
sessionMetaListenerMetas.removeListener(this.sendSessionStartEvent);
|
|
324
|
+
}
|
|
325
|
+
this.notifiedSession = undefined;
|
|
326
|
+
this.isResettingSession = false;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
SessionInstrumentation.prototype.destroy = function () {
|
|
330
|
+
this.unpatch();
|
|
162
331
|
};
|
|
163
332
|
return SessionInstrumentation;
|
|
164
333
|
}(faro_core_1.BaseInstrumentation));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseInstrumentation, dateNow, EVENT_SESSION_START, genShortID, VERSION } from '@grafana/faro-core';\nimport type { Config, Meta, MetaSession, TransportItem } from '@grafana/faro-core';\n\nimport type { ReactNativeFullConfig, ReactNativeSessionTrackingConfig } from '../../config/types';\n\nimport { minimalSessionDeviceAttributes, type SessionAttributes } from './sessionAttributes';\nimport { type FaroUserSession, getSessionManagerByConfig, isSampled } from './sessionManager';\nimport { MAX_SESSION_PERSISTENCE_TIME } from './sessionManager/sessionConstants';\nimport { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils';\nimport type { SessionManager } from './sessionManager/types';\n\n/**\n * Session instrumentation for React Native\n * Manages persistent or volatile sessions with expiration and inactivity tracking\n */\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = '@grafana/faro-react-native:instrumentation-session';\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n private sessionManagerInstance: InstanceType<SessionManager> | undefined;\n\n private getDefaultSessionDeviceAttributes(): SessionAttributes {\n const cfg = this.config as ReactNativeFullConfig;\n if (cfg.preloadedSessionDeviceAttributes != null) {\n return cfg.preloadedSessionDeviceAttributes;\n }\n return minimalSessionDeviceAttributes();\n }\n\n private sendSessionStartEvent(meta: Meta): void {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n }\n\n private createInitialSession(\n SessionManagerClass: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n emitSessionStartOnInit: boolean;\n } {\n let storedUserSession = SessionManagerClass.fetchUserSession();\n\n const sessionsConfigTyped = sessionsConfig as ReactNativeSessionTrackingConfig;\n const maxPersistenceMs = sessionsConfigTyped.maxSessionPersistenceTime ?? MAX_SESSION_PERSISTENCE_TIME;\n\n if (sessionsConfig.persistent && storedUserSession) {\n const now = dateNow();\n const shouldClearPersistentSession = storedUserSession.lastActivity < now - maxPersistenceMs;\n\n if (shouldClearPersistentSession) {\n SessionManagerClass.removeUserSession();\n storedUserSession = null;\n }\n }\n\n const defaultAttributes = this.getDefaultSessionDeviceAttributes();\n\n let emitSessionStartOnInit: boolean;\n let initialSession: FaroUserSession;\n\n if (isUserSessionValid(storedUserSession)) {\n const sessionId = storedUserSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: storedUserSession?.isSampled || false,\n started: storedUserSession?.started,\n });\n\n const storedUserSessionMeta = storedUserSession?.sessionMeta;\n\n // For resumed sessions we want to merge the previous overrides with the configured ones.\n // If the same key is present in both, the new one will override the old one.\n const overrides = { ...sessionsConfig.session?.overrides, ...storedUserSessionMeta?.overrides };\n\n initialSession.sessionMeta = {\n ...sessionsConfig.session,\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Merge with stored attributes\n ...storedUserSessionMeta?.attributes,\n // Default attributes take precedence (matching Flutter SDK behavior)\n ...defaultAttributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n overrides,\n };\n\n emitSessionStartOnInit = false;\n } else {\n const sessionId = sessionsConfig.session?.id ?? genShortID();\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: isSampled(),\n });\n\n const overrides = sessionsConfig.session?.overrides;\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n isSampled: initialSession.isSampled.toString(),\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Default attributes take precedence (matching Flutter SDK behavior)\n ...defaultAttributes,\n },\n // new session we don't care about previous overrides\n ...(overrides ? { overrides } : {}),\n };\n\n emitSessionStartOnInit = true;\n }\n\n return { initialSession, emitSessionStartOnInit };\n }\n\n private registerBeforeSendHook(SessionManagerClass: SessionManager) {\n const { updateSession } = new SessionManagerClass();\n\n this.transports?.addBeforeSendHooks((item: TransportItem) => {\n updateSession();\n\n const attributes = item.meta.session?.attributes;\n\n // Only filter out items when session is explicitly NOT sampled (isSampled='false')\n // If isSampled='true', remove the attribute before sending (it's internal)\n // If no isSampled attribute, pass through the item unchanged\n if (attributes?.['isSampled'] === 'false') {\n // Session is not sampled - drop this item\n return null;\n }\n\n if (attributes?.['isSampled'] === 'true') {\n // Session is sampled - remove internal isSampled attribute before sending\n let newItem: TransportItem = JSON.parse(JSON.stringify(item));\n\n const newAttributes = newItem.meta.session?.attributes;\n delete newAttributes?.['isSampled'];\n\n if (Object.keys(newAttributes ?? {}).length === 0) {\n delete newItem.meta.session?.attributes;\n }\n\n return newItem;\n }\n\n // No isSampled attribute or other value - pass through unchanged\n return item;\n });\n }\n\n initialize(): void {\n const sessionTrackingConfig = this.config.sessionTracking;\n\n if (!sessionTrackingConfig?.enabled) {\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n return;\n }\n\n const SessionManagerClass = getSessionManagerByConfig(sessionTrackingConfig);\n\n this.registerBeforeSendHook(SessionManagerClass);\n\n const { initialSession, emitSessionStartOnInit } = this.createInitialSession(\n SessionManagerClass,\n sessionTrackingConfig\n );\n SessionManagerClass.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n this.sessionManagerInstance = new SessionManagerClass();\n\n if (emitSessionStartOnInit) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n this.metas.addListener(this.sendSessionStartEvent.bind(this));\n }\n\n /**\n * Clean up session manager listeners\n */\n unpatch(): void {\n if (this.sessionManagerInstance && 'unpatch' in this.sessionManagerInstance) {\n this.sessionManagerInstance.unpatch();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseInstrumentation, dateNow, EVENT_SESSION_START, faro, VERSION } from '@grafana/faro-core';\nimport type {\n API,\n BeforeSendHook,\n Config,\n Meta,\n Metas,\n MetaSession,\n TransportItem,\n Transports,\n UserActionInternalInterface,\n} from '@grafana/faro-core';\n\nimport type { ReactNativeFullConfig, ReactNativeSessionTrackingConfig } from '../../config/types';\n\nimport { clearDirectSessionActivityHandler, registerDirectSessionActivityHandler } from './directSessionActivity';\nimport { classifySessionActivity, isRecoveredCrashItem, SessionActivityKind } from './sessionActivity';\nimport { minimalSessionDeviceAttributes, type SessionAttributes } from './sessionAttributes';\nimport { type FaroUserSession, getSessionManagerByConfig, isSampled } from './sessionManager';\nimport { MAX_SESSION_PERSISTENCE_TIME } from './sessionManager/sessionConstants';\nimport { createUserSessionObject, isUserSessionValid } from './sessionManager/sessionManagerUtils';\nimport type { SessionManager, SessionManagerInstance } from './sessionManager/types';\n\nconst SESSION_INSTRUMENTATION_NAME = '@grafana/faro-react-native:instrumentation-session';\n\n// Track the current session hook per transport so superseded hooks yield to a\n// replacement. The shared fallback preserves sampling decisions captured on\n// queued items after the owning instrumentation has detached.\nconst activeSessionBeforeSendHooks = new WeakMap<Transports, BeforeSendHook>();\nconst sessionSamplingFallbackHooks = new WeakMap<Transports, BeforeSendHook>();\n\nfunction applySessionSampling(item: TransportItem, fallbackSamplingDecision?: boolean): TransportItem | null {\n const attributes = item.meta.session?.attributes;\n const samplingAttribute = attributes?.['isSampled'] ?? fallbackSamplingDecision?.toString();\n\n if (samplingAttribute === 'false') {\n return null;\n }\n\n if (samplingAttribute !== 'true') {\n return item;\n }\n\n const sampledItem: TransportItem = {\n ...item,\n meta: {\n ...item.meta,\n session: item.meta.session\n ? {\n ...item.meta.session,\n attributes: item.meta.session.attributes ? { ...item.meta.session.attributes } : undefined,\n }\n : undefined,\n },\n };\n\n const sampledAttributes = sampledItem.meta.session?.attributes;\n delete sampledAttributes?.['isSampled'];\n\n if (Object.keys(sampledAttributes ?? {}).length === 0) {\n delete sampledItem.meta.session?.attributes;\n }\n\n return sampledItem;\n}\n\nfunction ensureSessionSamplingFallback(transports: Transports): void {\n if (sessionSamplingFallbackHooks.has(transports)) {\n return;\n }\n\n const fallbackHook: BeforeSendHook = (item) =>\n activeSessionBeforeSendHooks.has(transports) ? item : applySessionSampling(item);\n\n transports.addBeforeSendHooks(fallbackHook);\n sessionSamplingFallbackHooks.set(transports, fallbackHook);\n}\n\nfunction removeInternalSamplingAttribute(session: MetaSession | undefined): MetaSession | undefined {\n if (session?.attributes?.['isSampled'] == null) {\n return session;\n }\n\n const attributes = { ...session.attributes };\n delete attributes['isSampled'];\n\n return {\n ...session,\n attributes: Object.keys(attributes).length === 0 ? undefined : attributes,\n };\n}\n\n/**\n * Starts a new linked session at an application-defined boundary.\n *\n * Call this after changing or clearing the current user for logout, account\n * changes, or another boundary that must not share a session. Calls made\n * before Faro initializes, after teardown, or while session tracking is\n * disabled have no effect.\n */\nexport function startNewSession(): void {\n const instrumentation = faro?.instrumentations?.instrumentations.find(\n ({ name }) => name === SESSION_INSTRUMENTATION_NAME\n );\n\n if (\n instrumentation != null &&\n 'startNewSession' in instrumentation &&\n typeof instrumentation.startNewSession === 'function'\n ) {\n instrumentation.startNewSession();\n }\n}\n\n/**\n * Session instrumentation for React Native\n * Manages persistent or volatile sessions with expiration and inactivity tracking\n */\nexport class SessionInstrumentation extends BaseInstrumentation {\n readonly name = SESSION_INSTRUMENTATION_NAME;\n readonly version = VERSION;\n\n // previously notified session, to ensure we don't send session start\n // event twice for the same session\n private notifiedSession: MetaSession | undefined;\n private sessionManagerInstance: SessionManagerInstance | undefined;\n private isResettingSession = false;\n private unregisterDirectSessionActivity: (() => void) | undefined;\n private sessionMetaListenerMetas: Metas | undefined;\n private beforeSendHookApi: API | undefined;\n private beforeSendHook: BeforeSendHook | undefined;\n private beforeSendHookTransports: Transports | undefined;\n\n private getDefaultSessionDeviceAttributes(): SessionAttributes {\n const cfg = this.config as ReactNativeFullConfig;\n if (cfg.preloadedSessionDeviceAttributes != null) {\n return cfg.preloadedSessionDeviceAttributes;\n }\n return minimalSessionDeviceAttributes();\n }\n\n private readonly sendSessionStartEvent = (meta: Meta): void => {\n const session = meta.session;\n\n if (session && session.id !== this.notifiedSession?.id) {\n this.notifiedSession = session;\n // no need to add attributes and session id, they are included as part of meta\n // automatically\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n };\n\n private registerSessionMetaListener(): void {\n this.metas.addListener(this.sendSessionStartEvent);\n this.sessionMetaListenerMetas = this.metas;\n }\n\n private createInitialSession(\n SessionManagerClass: SessionManager,\n sessionsConfig: Required<Config>['sessionTracking']\n ): {\n initialSession: FaroUserSession;\n emitSessionStartOnInit: boolean;\n } {\n let storedUserSession = SessionManagerClass.fetchUserSession();\n\n const sessionsConfigTyped = sessionsConfig as ReactNativeSessionTrackingConfig;\n const maxPersistenceMs = sessionsConfigTyped.maxSessionPersistenceTime ?? MAX_SESSION_PERSISTENCE_TIME;\n\n if (sessionsConfig.persistent && storedUserSession) {\n const now = dateNow();\n const shouldClearPersistentSession =\n storedUserSession.started > now ||\n storedUserSession.lastActivity > now ||\n storedUserSession.lastActivity <= now - maxPersistenceMs;\n\n if (shouldClearPersistentSession) {\n SessionManagerClass.removeUserSession();\n storedUserSession = null;\n }\n }\n\n const defaultAttributes = this.getDefaultSessionDeviceAttributes();\n\n let emitSessionStartOnInit: boolean;\n let initialSession: FaroUserSession;\n\n if (!sessionsConfig.persistent && isUserSessionValid(storedUserSession)) {\n const sessionId = storedUserSession?.sessionId;\n\n initialSession = createUserSessionObject({\n sessionId,\n isSampled: storedUserSession?.isSampled || false,\n started: storedUserSession?.started,\n });\n\n const storedUserSessionMeta = storedUserSession?.sessionMeta;\n\n // For resumed sessions we want to merge the previous overrides with the configured ones.\n // If the same key is present in both, the new one will override the old one.\n const overrides = { ...sessionsConfig.session?.overrides, ...storedUserSessionMeta?.overrides };\n\n initialSession.sessionMeta = {\n ...sessionsConfig.session,\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Merge with stored attributes\n ...storedUserSessionMeta?.attributes,\n // Default attributes take precedence\n ...defaultAttributes,\n // For valid resumed sessions we do not want to recalculate the sampling decision on each init phase.\n isSampled: initialSession.isSampled.toString(),\n },\n overrides,\n };\n\n emitSessionStartOnInit = false;\n } else {\n initialSession = createUserSessionObject({\n sessionId: sessionsConfig.session?.id,\n isSampled: isSampled(),\n });\n\n const sessionId = initialSession.sessionId;\n const previousSessionId = storedUserSession?.sessionId === sessionId ? undefined : storedUserSession?.sessionId;\n const overrides = sessionsConfig.session?.overrides;\n\n initialSession.sessionMeta = {\n id: sessionId,\n attributes: {\n // Start with custom attributes from config\n ...sessionsConfig.session?.attributes,\n // Default attributes take precedence\n ...defaultAttributes,\n isSampled: initialSession.isSampled.toString(),\n ...(previousSessionId == null ? {} : { previousSession: previousSessionId }),\n },\n // new session we don't care about previous overrides\n ...(overrides ? { overrides } : {}),\n };\n\n emitSessionStartOnInit = true;\n }\n\n return { initialSession, emitSessionStartOnInit };\n }\n\n private registerBeforeSendHook(SessionManagerClass: SessionManager): void {\n const registeredTransports = this.transports;\n ensureSessionSamplingFallback(registeredTransports);\n\n const beforeSendHook: BeforeSendHook = (item: TransportItem) => {\n const activeBeforeSendHook = activeSessionBeforeSendHooks.get(registeredTransports);\n if (activeBeforeSendHook != null && activeBeforeSendHook !== beforeSendHook) {\n return item;\n }\n\n let nextItem = item;\n let fallbackSamplingDecision: boolean | undefined;\n const sessionManager = this.beforeSendHook === beforeSendHook ? this.sessionManagerInstance : undefined;\n\n if (sessionManager != null) {\n const storedSession = SessionManagerClass.fetchUserSession();\n const recoveredCrash = isRecoveredCrashItem(item, storedSession?.sessionId);\n // Ending an active action can send telemetry synchronously. Keep that\n // telemetry on the current session until the explicit reset completes.\n const checkedSession = recoveredCrash\n ? null\n : this.isResettingSession\n ? storedSession\n : sessionManager.checkSession(classifySessionActivity(item), storedSession);\n\n if (checkedSession?.sessionMeta != null && item.meta.session?.id !== checkedSession.sessionId) {\n nextItem = {\n ...item,\n meta: {\n ...item.meta,\n session: checkedSession.sessionMeta,\n },\n };\n }\n\n // New crash records carry the crash-time decision. Older records may not,\n // so retain the previous behavior and use the live session's stable\n // decision rather than implicitly sampling every recovered crash.\n fallbackSamplingDecision = recoveredCrash ? storedSession?.isSampled : checkedSession?.isSampled;\n }\n\n return applySessionSampling(nextItem, fallbackSamplingDecision);\n };\n\n this.beforeSendHook = beforeSendHook;\n this.beforeSendHookApi = this.api;\n this.beforeSendHookTransports = registeredTransports;\n registeredTransports.addBeforeSendHooks(beforeSendHook);\n activeSessionBeforeSendHooks.set(registeredTransports, beforeSendHook);\n }\n\n initialize(): void {\n // BaseInstrumentation instances can be registered more than once. Detach\n // every resource from the previous Faro instance before binding the next.\n this.unpatch();\n\n const sessionTrackingConfig = this.config.sessionTracking;\n\n // A new initialization owns direct-activity routing, including when\n // session tracking is disabled.\n clearDirectSessionActivityHandler();\n\n if (!sessionTrackingConfig?.enabled) {\n this.registerSessionMetaListener();\n return;\n }\n\n const SessionManagerClass = getSessionManagerByConfig(sessionTrackingConfig);\n\n // Constructing a manager registers an AppState subscription and a metas\n // listener, so exactly one instance is created and reused. It is also the\n // instance `unpatch()` cleans up.\n this.sessionManagerInstance = new SessionManagerClass(this.metas);\n\n this.registerBeforeSendHook(SessionManagerClass);\n\n const { initialSession, emitSessionStartOnInit } = this.createInitialSession(\n SessionManagerClass,\n sessionTrackingConfig\n );\n SessionManagerClass.storeUserSession(initialSession);\n\n const initialSessionMeta = initialSession.sessionMeta;\n this.notifiedSession = initialSessionMeta;\n this.api.setSession(initialSessionMeta);\n\n if (emitSessionStartOnInit) {\n this.api.pushEvent(EVENT_SESSION_START, {}, undefined, { skipDedupe: true });\n }\n\n this.unregisterDirectSessionActivity = registerDirectSessionActivityHandler(() => {\n this.sessionManagerInstance?.checkSession(SessionActivityKind.Meaningful);\n });\n\n this.registerSessionMetaListener();\n }\n\n /** Starts a new linked session immediately. */\n startNewSession(): void {\n if (this.sessionManagerInstance == null || this.isResettingSession) {\n return;\n }\n\n this.isResettingSession = true;\n try {\n try {\n const activeAction = this.api.getActiveUserAction?.() as UserActionInternalInterface | undefined;\n activeAction?.end();\n } catch (error) {\n this.logWarn('Failed to end the active user action before resetting the session:', error);\n }\n\n this.sessionManagerInstance.resetSession();\n } finally {\n this.isResettingSession = false;\n }\n }\n\n /**\n * Clean up session manager listeners\n */\n unpatch(): void {\n this.unregisterDirectSessionActivity?.();\n this.unregisterDirectSessionActivity = undefined;\n\n const beforeSendHook = this.beforeSendHook;\n const beforeSendHookApi = this.beforeSendHookApi;\n const beforeSendHookTransports = this.beforeSendHookTransports;\n const ownedActiveHook =\n beforeSendHook != null &&\n beforeSendHookTransports != null &&\n activeSessionBeforeSendHooks.get(beforeSendHookTransports) === beforeSendHook;\n\n // Stop the manager's metas synchronization before removing the internal\n // sampling marker. Keep the session hook active during that update so any\n // surviving metas listener that emits telemetry is still attributed and\n // filtered with the current session.\n this.sessionManagerInstance?.unpatch();\n\n try {\n if (ownedActiveHook && beforeSendHookApi) {\n const session = beforeSendHookApi.getSession();\n const sessionWithoutSamplingAttribute = removeInternalSamplingAttribute(session);\n if (sessionWithoutSamplingAttribute !== session) {\n this.isResettingSession = true;\n try {\n beforeSendHookApi.setSession(sessionWithoutSamplingAttribute);\n } finally {\n this.isResettingSession = false;\n }\n }\n }\n } finally {\n this.beforeSendHook = undefined;\n this.beforeSendHookApi = undefined;\n this.beforeSendHookTransports = undefined;\n if (beforeSendHook && beforeSendHookTransports) {\n if (ownedActiveHook) {\n activeSessionBeforeSendHooks.delete(beforeSendHookTransports);\n }\n beforeSendHookTransports.removeBeforeSendHooks(beforeSendHook);\n }\n\n this.sessionManagerInstance = undefined;\n\n const sessionMetaListenerMetas = this.sessionMetaListenerMetas;\n this.sessionMetaListenerMetas = undefined;\n if (sessionMetaListenerMetas) {\n sessionMetaListenerMetas.removeListener(this.sendSessionStartEvent);\n }\n\n this.notifiedSession = undefined;\n this.isResettingSession = false;\n }\n }\n\n destroy(): void {\n this.unpatch();\n }\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionActivityKind = void 0;
|
|
4
|
+
exports.classifySessionActivity = classifySessionActivity;
|
|
5
|
+
exports.isRecoveredCrashItem = isRecoveredCrashItem;
|
|
6
|
+
var faro_core_1 = require("@grafana/faro-core");
|
|
7
|
+
var utils_1 = require("../../navigation/utils");
|
|
8
|
+
var appState_1 = require("../appState");
|
|
9
|
+
var SessionActivityKind;
|
|
10
|
+
(function (SessionActivityKind) {
|
|
11
|
+
SessionActivityKind["Meaningful"] = "meaningful";
|
|
12
|
+
SessionActivityKind["Passive"] = "passive";
|
|
13
|
+
})(SessionActivityKind || (exports.SessionActivityKind = SessionActivityKind = {}));
|
|
14
|
+
/** Classifies how a transport item affects the session inactivity window. */
|
|
15
|
+
function classifySessionActivity(item) {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
var payload = item.payload;
|
|
18
|
+
if (payload.action != null) {
|
|
19
|
+
return SessionActivityKind.Meaningful;
|
|
20
|
+
}
|
|
21
|
+
if (item.type !== faro_core_1.TransportItemType.EVENT) {
|
|
22
|
+
return SessionActivityKind.Passive;
|
|
23
|
+
}
|
|
24
|
+
if (payload.name === faro_core_1.EVENT_VIEW_CHANGED || payload.name === utils_1.EVENT_NAVIGATION) {
|
|
25
|
+
return SessionActivityKind.Meaningful;
|
|
26
|
+
}
|
|
27
|
+
if (payload.name === appState_1.EVENT_APP_STATE_CHANGED &&
|
|
28
|
+
((_a = payload.attributes) === null || _a === void 0 ? void 0 : _a['fromState']) === 'background' &&
|
|
29
|
+
((_b = payload.attributes) === null || _b === void 0 ? void 0 : _b['toState']) === 'active') {
|
|
30
|
+
return SessionActivityKind.Meaningful;
|
|
31
|
+
}
|
|
32
|
+
return SessionActivityKind.Passive;
|
|
33
|
+
}
|
|
34
|
+
/** Recovered crashes keep the session captured by the previous process. */
|
|
35
|
+
function isRecoveredCrashItem(item, currentSessionId) {
|
|
36
|
+
var _a;
|
|
37
|
+
if (item.type !== faro_core_1.TransportItemType.EXCEPTION || ((_a = item.meta.session) === null || _a === void 0 ? void 0 : _a.id) == null) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
var payload = item.payload;
|
|
41
|
+
return payload.type === 'crash' && payload.fatal === true && item.meta.session.id !== currentSessionId;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=sessionActivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionActivity.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionActivity.ts"],"names":[],"mappings":";;;AAkBA,0DAwBC;AAQD,oDAOC;AAzDD,gDAA2E;AAG3E,gDAA0D;AAC1D,wCAAsD;AAEtD,IAAY,mBAGX;AAHD,WAAY,mBAAmB;IAC7B,gDAAyB,CAAA;IACzB,0CAAmB,CAAA;AACrB,CAAC,EAHW,mBAAmB,mCAAnB,mBAAmB,QAG9B;AAQD,6EAA6E;AAC7E,SAAgB,uBAAuB,CAAC,IAAmB;;IACzD,IAAM,OAAO,GAAG,IAAI,CAAC,OAA+B,CAAC;IAErD,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QAC3B,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,6BAAiB,CAAC,KAAK,EAAE,CAAC;QAC1C,OAAO,mBAAmB,CAAC,OAAO,CAAC;IACrC,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,KAAK,8BAAkB,IAAI,OAAO,CAAC,IAAI,KAAK,wBAAgB,EAAE,CAAC;QAC7E,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,IACE,OAAO,CAAC,IAAI,KAAK,kCAAuB;QACxC,CAAA,MAAA,OAAO,CAAC,UAAU,0CAAG,WAAW,CAAC,MAAK,YAAY;QAClD,CAAA,MAAA,OAAO,CAAC,UAAU,0CAAG,SAAS,CAAC,MAAK,QAAQ,EAC5C,CAAC;QACD,OAAO,mBAAmB,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,OAAO,mBAAmB,CAAC,OAAO,CAAC;AACrC,CAAC;AAOD,2EAA2E;AAC3E,SAAgB,oBAAoB,CAAC,IAAmB,EAAE,gBAAoC;;IAC5F,IAAI,IAAI,CAAC,IAAI,KAAK,6BAAiB,CAAC,SAAS,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,CAAC,OAAO,0CAAE,EAAE,KAAI,IAAI,EAAE,CAAC;QAC/E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAM,OAAO,GAAG,IAAI,CAAC,OAAuB,CAAC;IAC7C,OAAO,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,gBAAgB,CAAC;AACzG,CAAC","sourcesContent":["import { EVENT_VIEW_CHANGED, TransportItemType } from '@grafana/faro-core';\nimport type { EventAttributes, TransportItem } from '@grafana/faro-core';\n\nimport { EVENT_NAVIGATION } from '../../navigation/utils';\nimport { EVENT_APP_STATE_CHANGED } from '../appState';\n\nexport enum SessionActivityKind {\n Meaningful = 'meaningful',\n Passive = 'passive',\n}\n\ntype ActivityEventPayload = {\n action?: unknown;\n attributes?: EventAttributes;\n name?: string;\n};\n\n/** Classifies how a transport item affects the session inactivity window. */\nexport function classifySessionActivity(item: TransportItem): SessionActivityKind {\n const payload = item.payload as ActivityEventPayload;\n\n if (payload.action != null) {\n return SessionActivityKind.Meaningful;\n }\n\n if (item.type !== TransportItemType.EVENT) {\n return SessionActivityKind.Passive;\n }\n\n if (payload.name === EVENT_VIEW_CHANGED || payload.name === EVENT_NAVIGATION) {\n return SessionActivityKind.Meaningful;\n }\n\n if (\n payload.name === EVENT_APP_STATE_CHANGED &&\n payload.attributes?.['fromState'] === 'background' &&\n payload.attributes?.['toState'] === 'active'\n ) {\n return SessionActivityKind.Meaningful;\n }\n\n return SessionActivityKind.Passive;\n}\n\ntype CrashPayload = {\n fatal?: unknown;\n type?: unknown;\n};\n\n/** Recovered crashes keep the session captured by the previous process. */\nexport function isRecoveredCrashItem(item: TransportItem, currentSessionId: string | undefined): boolean {\n if (item.type !== TransportItemType.EXCEPTION || item.meta.session?.id == null) {\n return false;\n }\n\n const payload = item.payload as CrashPayload;\n return payload.type === 'crash' && payload.fatal === true && item.meta.session.id !== currentSessionId;\n}\n"]}
|
|
@@ -57,6 +57,7 @@ exports.loadSessionDeviceAttributesForInit = loadSessionDeviceAttributesForInit;
|
|
|
57
57
|
var react_native_1 = require("react-native");
|
|
58
58
|
var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
59
59
|
var installationId_1 = require("./installationId");
|
|
60
|
+
var sessionProcess_1 = require("./sessionProcess");
|
|
60
61
|
/**
|
|
61
62
|
* React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.
|
|
62
63
|
*/
|
|
@@ -108,7 +109,7 @@ function getMobileDeviceType(isTablet) {
|
|
|
108
109
|
return undefined;
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
111
|
-
* Get OS detail string
|
|
112
|
+
* Get OS detail string for session attributes.
|
|
112
113
|
* iOS: "iOS 17.0"
|
|
113
114
|
* Android: "Android 15 (SDK 35)"
|
|
114
115
|
*/
|
|
@@ -160,16 +161,16 @@ function getDeviceOsBuildId() {
|
|
|
160
161
|
* No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.
|
|
161
162
|
*/
|
|
162
163
|
function minimalSessionDeviceAttributes() {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
};
|
|
164
|
+
var processInfo = (0, sessionProcess_1.getSessionProcessInfo)();
|
|
165
|
+
return __assign({ react_native_version: getReactNativeVersion() }, (processInfo == null ? {} : { process_name: processInfo.identifier }));
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* Get all session attributes
|
|
169
169
|
* These attributes are automatically included with every telemetry event
|
|
170
170
|
*
|
|
171
|
-
* Core attributes
|
|
171
|
+
* Core session attributes:
|
|
172
172
|
* - react_native_version (RN framework in the host app)
|
|
173
|
+
* - process_name (Android process name or iOS bundle identifier)
|
|
173
174
|
* - device_os, device_os_version, device_os_detail
|
|
174
175
|
* - device_manufacturer, device_model, device_model_name
|
|
175
176
|
* - device_brand, device_is_physical, device_id
|
|
@@ -192,7 +193,7 @@ function getSessionAttributes() {
|
|
|
192
193
|
}
|
|
193
194
|
function collectMobileMeta() {
|
|
194
195
|
return __awaiter(this, void 0, void 0, function () {
|
|
195
|
-
var _a, deviceOsDetail, deviceOsBuildId, installationId, systemName, systemVersion, manufacturer, model, modelIdentifier, deviceName, brand, isEmulator, isTablet, deviceType, totalMemory, usedMemory,
|
|
196
|
+
var _a, deviceOsDetail, deviceOsBuildId, installationId, systemName, systemVersion, manufacturer, model, modelIdentifier, deviceName, brand, isEmulator, isTablet, deviceType, totalMemory, usedMemory, batteryLevel, isCharging, lowPowerMode, carrier, battery, _error_3, _b, _error_4, _c, _error_5, carrierName, _error_6, attributes, appMeta, structuredDeviceBrand, structuredDeviceManufacturer, osMeta, _error_7, installationId;
|
|
196
197
|
return __generator(this, function (_d) {
|
|
197
198
|
switch (_d.label) {
|
|
198
199
|
case 0:
|
|
@@ -216,7 +217,6 @@ function collectMobileMeta() {
|
|
|
216
217
|
deviceType = getMobileDeviceType(isTablet);
|
|
217
218
|
totalMemory = react_native_device_info_1.default.getTotalMemorySync();
|
|
218
219
|
usedMemory = react_native_device_info_1.default.getUsedMemorySync();
|
|
219
|
-
reactNativeVersion = getReactNativeVersion();
|
|
220
220
|
batteryLevel = void 0;
|
|
221
221
|
isCharging = void 0;
|
|
222
222
|
lowPowerMode = void 0;
|
|
@@ -269,7 +269,7 @@ function collectMobileMeta() {
|
|
|
269
269
|
_error_6 = _d.sent();
|
|
270
270
|
return [3 /*break*/, 15];
|
|
271
271
|
case 15:
|
|
272
|
-
attributes = __assign(__assign(__assign({
|
|
272
|
+
attributes = __assign(__assign(__assign(__assign(__assign({}, minimalSessionDeviceAttributes()), { device_os: systemName, device_os_version: systemVersion, device_os_detail: deviceOsDetail, device_manufacturer: manufacturer.toLowerCase(), device_model: model, device_model_name: deviceName, device_brand: brand, device_is_physical: String(!isEmulator) }), (installationId ? { device_id: installationId } : {})), (deviceType ? { device_type: deviceType } : {})), { device_memory_total: String(totalMemory), device_memory_used: String(usedMemory), device_battery_level: batteryLevel, device_is_charging: isCharging, device_low_power_mode: lowPowerMode, device_carrier: carrier });
|
|
273
273
|
appMeta = installationId ? { installationId: installationId } : {};
|
|
274
274
|
structuredDeviceBrand = getStructuredDeviceBrand(model, brand);
|
|
275
275
|
structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);
|