@grafana/faro-react-native 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +118 -36
- package/android/consumer-proguard-rules.pro +2 -0
- package/android/src/main/java/com/grafana/faro/reactnative/ANRTracker.kt +61 -9
- package/android/src/main/java/com/grafana/faro/reactnative/AnrThreadDumpParser.kt +70 -0
- package/android/src/main/java/com/grafana/faro/reactnative/ApplicationExitTraceReader.kt +142 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrCache.kt +163 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroAnrReporter.kt +163 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashReporter.kt +243 -50
- package/android/src/main/java/com/grafana/faro/reactnative/FaroCrashTraceCache.kt +75 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroNativeCrashTrace.kt +39 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativeModule.kt +99 -8
- package/android/src/main/java/com/grafana/faro/reactnative/FaroReactNativePackage.kt +1 -0
- package/android/src/main/java/com/grafana/faro/reactnative/FaroUncaughtExceptionHandler.kt +62 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneBacktraceFormatter.kt +117 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneModels.kt +35 -0
- package/android/src/main/java/com/grafana/faro/reactnative/TombstoneWireParser.kt +235 -0
- package/android/src/main/proto/tombstone.proto +62 -0
- package/android/src/test/java/com/grafana/faro/reactnative/AnrStackFiltersTest.kt +28 -0
- package/android/src/test/java/com/grafana/faro/reactnative/AnrThreadDumpParserTest.kt +38 -0
- package/android/src/test/java/com/grafana/faro/reactnative/FaroAnrCacheTest.kt +81 -0
- package/android/src/test/java/com/grafana/faro/reactnative/TombstoneWireParserTest.kt +51 -0
- package/dist/cjs/config/getRNInstrumentations.js +3 -1
- package/dist/cjs/config/getRNInstrumentations.js.map +1 -1
- package/dist/cjs/config/makeRNConfig.js +48 -9
- package/dist/cjs/config/makeRNConfig.js.map +1 -1
- package/dist/cjs/config/types.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 +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/initialize.js +14 -8
- package/dist/cjs/initialize.js.map +1 -1
- package/dist/cjs/instrumentations/anr/anrStack.js +19 -0
- package/dist/cjs/instrumentations/anr/anrStack.js.map +1 -0
- package/dist/cjs/instrumentations/anr/instrumentation.js +374 -72
- package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/anr/types.js.map +1 -1
- package/dist/cjs/instrumentations/console/index.js +5 -1
- package/dist/cjs/instrumentations/console/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +110 -103
- package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +41 -0
- package/dist/cjs/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +87 -0
- package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js +123 -0
- package/dist/cjs/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/index.js +12 -0
- package/dist/cjs/instrumentations/crashReporting/android/index.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js +11 -0
- package/dist/cjs/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +181 -0
- package/dist/cjs/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/index.js +35 -2
- package/dist/cjs/instrumentations/crashReporting/index.js.map +1 -1
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +78 -0
- package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js +103 -0
- package/dist/cjs/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/index.js +11 -0
- package/dist/cjs/instrumentations/crashReporting/ios/index.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js +48 -0
- package/dist/cjs/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
- package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/cjs/instrumentations/errors/index.js +2 -1
- package/dist/cjs/instrumentations/errors/index.js.map +1 -1
- package/dist/cjs/instrumentations/session/installationId.js +91 -0
- package/dist/cjs/instrumentations/session/installationId.js.map +1 -0
- package/dist/cjs/instrumentations/session/sessionAttributes.js +152 -89
- package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/cjs/metas/appBuildIdentity.js +95 -0
- package/dist/cjs/metas/appBuildIdentity.js.map +1 -0
- package/dist/cjs/testUtils/mockDeviceInfo.js +5 -0
- package/dist/cjs/testUtils/mockDeviceInfo.js.map +1 -1
- package/dist/cjs/testUtils/setupTests.js +7 -0
- package/dist/cjs/testUtils/setupTests.js.map +1 -1
- package/dist/esm/config/getRNInstrumentations.js +3 -1
- package/dist/esm/config/getRNInstrumentations.js.map +1 -1
- package/dist/esm/config/makeRNConfig.js +49 -10
- package/dist/esm/config/makeRNConfig.js.map +1 -1
- package/dist/esm/config/types.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 +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/initialize.js +11 -5
- package/dist/esm/initialize.js.map +1 -1
- package/dist/esm/instrumentations/anr/anrStack.js +16 -0
- package/dist/esm/instrumentations/anr/anrStack.js.map +1 -0
- package/dist/esm/instrumentations/anr/instrumentation.js +260 -67
- package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/anr/types.js.map +1 -1
- package/dist/esm/instrumentations/console/index.js +5 -1
- package/dist/esm/instrumentations/console/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/{instrumentation.js → BaseCrashReportingInstrumentation.js} +76 -94
- package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js +18 -0
- package/dist/esm/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +56 -0
- package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js +116 -0
- package/dist/esm/instrumentations/crashReporting/android/crashErrorMessage.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/index.js +4 -0
- package/dist/esm/instrumentations/crashReporting/android/index.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js +8 -0
- package/dist/esm/instrumentations/crashReporting/android/nativeTombstoneTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js +174 -0
- package/dist/esm/instrumentations/crashReporting/android/parseAndroidCrashTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/index.js +35 -1
- package/dist/esm/instrumentations/crashReporting/index.js.map +1 -1
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +56 -0
- package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js +98 -0
- package/dist/esm/instrumentations/crashReporting/ios/crashErrorMessage.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/index.js +4 -0
- package/dist/esm/instrumentations/crashReporting/ios/index.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js +44 -0
- package/dist/esm/instrumentations/crashReporting/ios/parseIosCrashTrace.js.map +1 -0
- package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
- package/dist/esm/instrumentations/errors/index.js +2 -1
- package/dist/esm/instrumentations/errors/index.js.map +1 -1
- package/dist/esm/instrumentations/session/installationId.js +48 -0
- package/dist/esm/instrumentations/session/installationId.js.map +1 -0
- package/dist/esm/instrumentations/session/sessionAttributes.js +83 -38
- package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
- package/dist/esm/metas/appBuildIdentity.js +56 -0
- package/dist/esm/metas/appBuildIdentity.js.map +1 -0
- package/dist/esm/testUtils/mockDeviceInfo.js +5 -0
- package/dist/esm/testUtils/mockDeviceInfo.js.map +1 -1
- package/dist/esm/testUtils/setupTests.js +7 -0
- package/dist/esm/testUtils/setupTests.js.map +1 -1
- package/dist/types/config/makeRNConfig.d.ts +4 -3
- package/dist/types/config/types.d.ts +2 -1
- package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/initialize.d.ts +4 -2
- package/dist/types/instrumentations/anr/anrStack.d.ts +7 -0
- package/dist/types/instrumentations/anr/instrumentation.d.ts +23 -28
- package/dist/types/instrumentations/anr/types.d.ts +5 -1
- package/dist/types/instrumentations/appState/index.d.ts +1 -1
- package/dist/types/instrumentations/console/index.d.ts +1 -1
- package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +56 -0
- package/dist/types/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.d.ts +12 -0
- package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +26 -0
- package/dist/types/instrumentations/crashReporting/android/crashErrorMessage.d.ts +23 -0
- package/dist/types/instrumentations/crashReporting/android/index.d.ts +4 -0
- package/dist/types/instrumentations/crashReporting/android/nativeTombstoneTrace.d.ts +2 -0
- package/dist/types/instrumentations/crashReporting/android/parseAndroidCrashTrace.d.ts +45 -0
- package/dist/types/instrumentations/crashReporting/index.d.ts +25 -2
- package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +28 -0
- package/dist/types/instrumentations/crashReporting/ios/crashErrorMessage.d.ts +14 -0
- package/dist/types/instrumentations/crashReporting/ios/index.d.ts +4 -0
- package/dist/types/instrumentations/crashReporting/ios/parseIosCrashTrace.d.ts +38 -0
- package/dist/types/instrumentations/crashReporting/types.d.ts +18 -51
- package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/http/index.d.ts +1 -1
- package/dist/types/instrumentations/performance/index.d.ts +1 -1
- package/dist/types/instrumentations/session/index.d.ts +1 -1
- package/dist/types/instrumentations/session/installationId.d.ts +1 -0
- package/dist/types/instrumentations/session/sessionAttributes.d.ts +13 -4
- package/dist/types/instrumentations/startup/index.d.ts +1 -1
- package/dist/types/instrumentations/userActions/index.d.ts +1 -1
- package/dist/types/instrumentations/view/index.d.ts +1 -1
- package/dist/types/instrumentations/xhr/index.d.ts +1 -1
- package/dist/types/metas/appBuildIdentity.d.ts +16 -0
- package/dist/types/testUtils/mockFaroReactNativeTracing.d.ts +1 -1
- package/dist/types/transports/console/transport.d.ts +1 -1
- package/dist/types/transports/fetch/transport.d.ts +1 -1
- package/dist/types/transports/offline/transport.d.ts +1 -1
- package/package.json +4 -4
- package/src/config/getRNInstrumentations.ts +5 -1
- package/src/config/makeRNConfig.test.ts +59 -3
- package/src/config/makeRNConfig.ts +48 -9
- package/src/config/types.ts +2 -1
- package/src/generated/faroRNPackageMeta.ts +1 -1
- package/src/index.ts +2 -1
- package/src/initialize.test.ts +71 -15
- package/src/initialize.ts +11 -5
- package/src/instrumentations/anr/anrStack.test.ts +27 -0
- package/src/instrumentations/anr/anrStack.ts +19 -0
- package/src/instrumentations/anr/instrumentation.test.ts +45 -0
- package/src/instrumentations/anr/instrumentation.ts +301 -67
- package/src/instrumentations/anr/types.ts +7 -1
- package/src/instrumentations/console/index.ts +5 -1
- package/src/instrumentations/console/instrumentation.test.ts +5 -0
- package/src/instrumentations/crashReporting/{instrumentation.ts → BaseCrashReportingInstrumentation.ts} +119 -93
- package/src/instrumentations/crashReporting/NoOpCrashReportingInstrumentation.ts +23 -0
- package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +62 -0
- package/src/instrumentations/crashReporting/android/crashErrorMessage.test.ts +182 -0
- package/src/instrumentations/crashReporting/android/crashErrorMessage.ts +135 -0
- package/src/instrumentations/crashReporting/android/index.ts +4 -0
- package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.test.ts +19 -0
- package/src/instrumentations/crashReporting/android/nativeTombstoneTrace.ts +8 -0
- package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.test.ts +232 -0
- package/src/instrumentations/crashReporting/android/parseAndroidCrashTrace.ts +235 -0
- package/src/instrumentations/crashReporting/index.ts +43 -2
- package/src/instrumentations/crashReporting/instrumentation.test.ts +42 -0
- package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +62 -0
- package/src/instrumentations/crashReporting/ios/crashErrorMessage.test.ts +170 -0
- package/src/instrumentations/crashReporting/ios/crashErrorMessage.ts +111 -0
- package/src/instrumentations/crashReporting/ios/index.ts +4 -0
- package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.test.ts +86 -0
- package/src/instrumentations/crashReporting/ios/parseIosCrashTrace.ts +83 -0
- package/src/instrumentations/crashReporting/types.ts +19 -58
- package/src/instrumentations/errors/index.ts +2 -1
- package/src/instrumentations/errors/instrumentation.test.ts +8 -2
- package/src/instrumentations/errors/stackTraceParser.test.ts +1 -1
- package/src/instrumentations/session/installationId.ts +43 -0
- package/src/instrumentations/session/sessionAttributes.test.ts +260 -30
- package/src/instrumentations/session/sessionAttributes.ts +112 -22
- package/src/metas/appBuildIdentity.test.ts +48 -0
- package/src/metas/appBuildIdentity.ts +50 -0
- package/src/testUtils/mockDeviceInfo.ts +5 -0
- package/src/testUtils/setupTests.ts +7 -0
- package/dist/cjs/instrumentations/crashReporting/instrumentation.js.map +0 -1
- package/dist/esm/instrumentations/crashReporting/instrumentation.js.map +0 -1
- package/dist/types/instrumentations/crashReporting/instrumentation.d.ts +0 -58
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
2
13
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
14
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
15
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -41,9 +52,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
41
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
53
|
exports.minimalSessionDeviceAttributes = minimalSessionDeviceAttributes;
|
|
43
54
|
exports.getSessionAttributes = getSessionAttributes;
|
|
55
|
+
exports.loadMobileMetaForInit = loadMobileMetaForInit;
|
|
44
56
|
exports.loadSessionDeviceAttributesForInit = loadSessionDeviceAttributesForInit;
|
|
45
57
|
var react_native_1 = require("react-native");
|
|
46
58
|
var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
59
|
+
var installationId_1 = require("./installationId");
|
|
47
60
|
/**
|
|
48
61
|
* React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.
|
|
49
62
|
*/
|
|
@@ -64,28 +77,35 @@ function getReactNativeVersion() {
|
|
|
64
77
|
return 'unknown';
|
|
65
78
|
}
|
|
66
79
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
function getStructuredDeviceBrand(model, brand) {
|
|
81
|
+
if (react_native_1.Platform.OS !== 'ios') {
|
|
82
|
+
return brand;
|
|
83
|
+
}
|
|
84
|
+
return model.toLowerCase().includes('ipad') ? 'iPad' : 'iPhone';
|
|
85
|
+
}
|
|
86
|
+
function getStructuredDeviceManufacturer(manufacturer) {
|
|
87
|
+
return react_native_1.Platform.OS === 'ios' ? manufacturer.toLowerCase() : manufacturer;
|
|
88
|
+
}
|
|
89
|
+
function getStructuredDeviceModelIdentifier(model) {
|
|
90
|
+
// Android getDeviceId() returns a board code, so use Build.MODEL for the Faro
|
|
91
|
+
// model identifier.
|
|
92
|
+
if (react_native_1.Platform.OS === 'android') {
|
|
93
|
+
return model;
|
|
94
|
+
}
|
|
95
|
+
// React Native reports iPhone and iPadOS apps as Platform.OS === 'ios'.
|
|
96
|
+
// react-native-device-info exposes the Apple hardware identifier here.
|
|
97
|
+
if (react_native_1.Platform.OS === 'ios') {
|
|
98
|
+
return react_native_device_info_1.default.getDeviceId();
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
function getMobileDeviceType(isTablet) {
|
|
103
|
+
// iPadOS is still reported as Platform.OS === 'ios'; DeviceInfo.isTablet()
|
|
104
|
+
// distinguishes iPad/tablet form factor from phone form factor.
|
|
105
|
+
if (react_native_1.Platform.OS === 'ios' || react_native_1.Platform.OS === 'android') {
|
|
106
|
+
return isTablet ? 'tablet' : 'mobile';
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
89
109
|
}
|
|
90
110
|
/**
|
|
91
111
|
* Get OS detail string matching Flutter SDK format
|
|
@@ -94,7 +114,7 @@ function getDeviceId() {
|
|
|
94
114
|
*/
|
|
95
115
|
function getDeviceOsDetail() {
|
|
96
116
|
return __awaiter(this, void 0, void 0, function () {
|
|
97
|
-
var systemName, systemVersion, apiLevel,
|
|
117
|
+
var systemName, systemVersion, apiLevel, _error_1;
|
|
98
118
|
return __generator(this, function (_a) {
|
|
99
119
|
switch (_a.label) {
|
|
100
120
|
case 0:
|
|
@@ -109,13 +129,32 @@ function getDeviceOsDetail() {
|
|
|
109
129
|
apiLevel = _a.sent();
|
|
110
130
|
return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion, " (SDK ").concat(apiLevel, ")")];
|
|
111
131
|
case 3:
|
|
112
|
-
|
|
132
|
+
_error_1 = _a.sent();
|
|
113
133
|
return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion)];
|
|
114
134
|
case 4: return [2 /*return*/, "".concat(systemName, " ").concat(systemVersion)];
|
|
115
135
|
}
|
|
116
136
|
});
|
|
117
137
|
});
|
|
118
138
|
}
|
|
139
|
+
function getDeviceOsBuildId() {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
141
|
+
var buildId, _error_2;
|
|
142
|
+
return __generator(this, function (_a) {
|
|
143
|
+
switch (_a.label) {
|
|
144
|
+
case 0:
|
|
145
|
+
_a.trys.push([0, 2, , 3]);
|
|
146
|
+
return [4 /*yield*/, react_native_device_info_1.default.getBuildId()];
|
|
147
|
+
case 1:
|
|
148
|
+
buildId = _a.sent();
|
|
149
|
+
return [2 /*return*/, buildId && buildId !== 'unknown' ? buildId : undefined];
|
|
150
|
+
case 2:
|
|
151
|
+
_error_2 = _a.sent();
|
|
152
|
+
return [2 /*return*/, undefined];
|
|
153
|
+
case 3: return [2 /*return*/];
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
119
158
|
/**
|
|
120
159
|
* Session attributes without device props when async collection or DeviceInfo is unavailable.
|
|
121
160
|
* No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.
|
|
@@ -143,25 +182,38 @@ function minimalSessionDeviceAttributes() {
|
|
|
143
182
|
*/
|
|
144
183
|
function getSessionAttributes() {
|
|
145
184
|
return __awaiter(this, void 0, void 0, function () {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
185
|
+
return __generator(this, function (_a) {
|
|
186
|
+
switch (_a.label) {
|
|
187
|
+
case 0: return [4 /*yield*/, collectMobileMeta()];
|
|
188
|
+
case 1: return [2 /*return*/, (_a.sent()).sessionAttributes];
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function collectMobileMeta() {
|
|
194
|
+
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, reactNativeVersion, 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
|
+
return __generator(this, function (_d) {
|
|
197
|
+
switch (_d.label) {
|
|
149
198
|
case 0:
|
|
150
|
-
|
|
151
|
-
return [4 /*yield*/,
|
|
199
|
+
_d.trys.push([0, 16, , 18]);
|
|
200
|
+
return [4 /*yield*/, Promise.all([
|
|
201
|
+
getDeviceOsDetail(),
|
|
202
|
+
getDeviceOsBuildId(),
|
|
203
|
+
(0, installationId_1.getInstallationId)(),
|
|
204
|
+
])];
|
|
152
205
|
case 1:
|
|
153
|
-
|
|
154
|
-
return [4 /*yield*/, getDeviceOsDetail()];
|
|
155
|
-
case 2:
|
|
156
|
-
deviceOsDetail = _c.sent();
|
|
206
|
+
_a = _d.sent(), deviceOsDetail = _a[0], deviceOsBuildId = _a[1], installationId = _a[2];
|
|
157
207
|
systemName = react_native_device_info_1.default.getSystemName();
|
|
158
208
|
systemVersion = react_native_device_info_1.default.getSystemVersion();
|
|
159
209
|
manufacturer = react_native_device_info_1.default.getManufacturerSync();
|
|
160
210
|
model = react_native_device_info_1.default.getModel();
|
|
211
|
+
modelIdentifier = getStructuredDeviceModelIdentifier(model);
|
|
161
212
|
deviceName = react_native_device_info_1.default.getDeviceNameSync();
|
|
162
213
|
brand = react_native_device_info_1.default.getBrand();
|
|
163
214
|
isEmulator = react_native_device_info_1.default.isEmulatorSync();
|
|
164
215
|
isTablet = react_native_device_info_1.default.isTablet();
|
|
216
|
+
deviceType = getMobileDeviceType(isTablet);
|
|
165
217
|
totalMemory = react_native_device_info_1.default.getTotalMemorySync();
|
|
166
218
|
usedMemory = react_native_device_info_1.default.getUsedMemorySync();
|
|
167
219
|
reactNativeVersion = getReactNativeVersion();
|
|
@@ -169,82 +221,93 @@ function getSessionAttributes() {
|
|
|
169
221
|
isCharging = void 0;
|
|
170
222
|
lowPowerMode = void 0;
|
|
171
223
|
carrier = void 0;
|
|
172
|
-
|
|
173
|
-
case
|
|
174
|
-
|
|
224
|
+
_d.label = 2;
|
|
225
|
+
case 2:
|
|
226
|
+
_d.trys.push([2, 4, , 5]);
|
|
175
227
|
return [4 /*yield*/, react_native_device_info_1.default.getBatteryLevel()];
|
|
176
|
-
case
|
|
177
|
-
battery =
|
|
228
|
+
case 3:
|
|
229
|
+
battery = _d.sent();
|
|
178
230
|
if (battery >= 0) {
|
|
179
231
|
batteryLevel = String(Math.round(battery * 100));
|
|
180
232
|
}
|
|
181
|
-
return [3 /*break*/,
|
|
233
|
+
return [3 /*break*/, 5];
|
|
234
|
+
case 4:
|
|
235
|
+
_error_3 = _d.sent();
|
|
236
|
+
return [3 /*break*/, 5];
|
|
182
237
|
case 5:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
case 6:
|
|
186
|
-
_c.trys.push([6, 8, , 9]);
|
|
187
|
-
_a = String;
|
|
238
|
+
_d.trys.push([5, 7, , 8]);
|
|
239
|
+
_b = String;
|
|
188
240
|
return [4 /*yield*/, react_native_device_info_1.default.isBatteryCharging()];
|
|
241
|
+
case 6:
|
|
242
|
+
isCharging = _b.apply(void 0, [_d.sent()]);
|
|
243
|
+
return [3 /*break*/, 8];
|
|
189
244
|
case 7:
|
|
190
|
-
|
|
191
|
-
return [3 /*break*/,
|
|
245
|
+
_error_4 = _d.sent();
|
|
246
|
+
return [3 /*break*/, 8];
|
|
192
247
|
case 8:
|
|
193
|
-
|
|
194
|
-
return [3 /*break*/,
|
|
195
|
-
|
|
196
|
-
_c.trys.push([9, 12, , 13]);
|
|
197
|
-
if (!('isPowerSaveMode' in react_native_device_info_1.default)) return [3 /*break*/, 11];
|
|
198
|
-
_b = String;
|
|
248
|
+
_d.trys.push([8, 11, , 12]);
|
|
249
|
+
if (!('isPowerSaveMode' in react_native_device_info_1.default)) return [3 /*break*/, 10];
|
|
250
|
+
_c = String;
|
|
199
251
|
return [4 /*yield*/, react_native_device_info_1.default.isPowerSaveMode()];
|
|
200
|
-
case
|
|
201
|
-
lowPowerMode =
|
|
202
|
-
|
|
203
|
-
case
|
|
252
|
+
case 9:
|
|
253
|
+
lowPowerMode = _c.apply(void 0, [_d.sent()]);
|
|
254
|
+
_d.label = 10;
|
|
255
|
+
case 10: return [3 /*break*/, 12];
|
|
256
|
+
case 11:
|
|
257
|
+
_error_5 = _d.sent();
|
|
258
|
+
return [3 /*break*/, 12];
|
|
204
259
|
case 12:
|
|
205
|
-
|
|
206
|
-
return [3 /*break*/, 13];
|
|
207
|
-
case 13:
|
|
208
|
-
_c.trys.push([13, 15, , 16]);
|
|
260
|
+
_d.trys.push([12, 14, , 15]);
|
|
209
261
|
return [4 /*yield*/, react_native_device_info_1.default.getCarrier()];
|
|
210
|
-
case
|
|
211
|
-
carrierName =
|
|
262
|
+
case 13:
|
|
263
|
+
carrierName = _d.sent();
|
|
212
264
|
if (carrierName && carrierName !== 'unknown') {
|
|
213
265
|
carrier = carrierName;
|
|
214
266
|
}
|
|
215
|
-
return [3 /*break*/,
|
|
267
|
+
return [3 /*break*/, 15];
|
|
268
|
+
case 14:
|
|
269
|
+
_error_6 = _d.sent();
|
|
270
|
+
return [3 /*break*/, 15];
|
|
216
271
|
case 15:
|
|
217
|
-
|
|
218
|
-
|
|
272
|
+
attributes = __assign(__assign(__assign({ react_native_version: reactNativeVersion, 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
|
+
appMeta = installationId ? { installationId: installationId } : {};
|
|
274
|
+
structuredDeviceBrand = getStructuredDeviceBrand(model, brand);
|
|
275
|
+
structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);
|
|
276
|
+
osMeta = __assign(__assign({}, (deviceOsBuildId ? { build_id: deviceOsBuildId } : {})), { detail: deviceOsDetail, name: systemName, version: systemVersion });
|
|
277
|
+
return [2 /*return*/, {
|
|
278
|
+
sessionAttributes: attributes,
|
|
279
|
+
meta: {
|
|
280
|
+
app: appMeta,
|
|
281
|
+
device: __assign(__assign(__assign({ brand: structuredDeviceBrand, is_physical: !isEmulator, manufacturer: structuredDeviceManufacturer }, (modelIdentifier ? { model_identifier: modelIdentifier } : {})), { model_name: model }), (deviceType ? { type: deviceType } : {})),
|
|
282
|
+
os: osMeta,
|
|
283
|
+
},
|
|
284
|
+
}];
|
|
219
285
|
case 16:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
device_os: systemName,
|
|
223
|
-
device_os_version: systemVersion,
|
|
224
|
-
device_os_detail: deviceOsDetail,
|
|
225
|
-
device_manufacturer: manufacturer.toLowerCase(),
|
|
226
|
-
device_model: model,
|
|
227
|
-
device_model_name: deviceName,
|
|
228
|
-
device_brand: brand,
|
|
229
|
-
device_is_physical: String(!isEmulator),
|
|
230
|
-
device_id: deviceId,
|
|
231
|
-
device_type: isTablet ? 'tablet' : 'mobile',
|
|
232
|
-
device_memory_total: String(totalMemory),
|
|
233
|
-
device_memory_used: String(usedMemory),
|
|
234
|
-
device_battery_level: batteryLevel,
|
|
235
|
-
device_is_charging: isCharging,
|
|
236
|
-
device_low_power_mode: lowPowerMode,
|
|
237
|
-
device_carrier: carrier,
|
|
238
|
-
};
|
|
239
|
-
return [2 /*return*/, attributes];
|
|
286
|
+
_error_7 = _d.sent();
|
|
287
|
+
return [4 /*yield*/, (0, installationId_1.getInstallationId)()];
|
|
240
288
|
case 17:
|
|
241
|
-
|
|
242
|
-
return [2 /*return*/,
|
|
289
|
+
installationId = _d.sent();
|
|
290
|
+
return [2 /*return*/, {
|
|
291
|
+
sessionAttributes: minimalSessionDeviceAttributes(),
|
|
292
|
+
meta: {
|
|
293
|
+
app: installationId ? { installationId: installationId } : {},
|
|
294
|
+
},
|
|
295
|
+
}];
|
|
243
296
|
case 18: return [2 /*return*/];
|
|
244
297
|
}
|
|
245
298
|
});
|
|
246
299
|
});
|
|
247
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Get structured mobile meta plus flat session attributes for async `initializeFaro`.
|
|
303
|
+
*/
|
|
304
|
+
function loadMobileMetaForInit() {
|
|
305
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
306
|
+
return __generator(this, function (_a) {
|
|
307
|
+
return [2 /*return*/, collectMobileMeta()];
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}
|
|
248
311
|
/**
|
|
249
312
|
* Await full async session device attributes (battery, carrier, etc.), then fall back to
|
|
250
313
|
* {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.
|
|
@@ -256,8 +319,8 @@ function loadSessionDeviceAttributesForInit() {
|
|
|
256
319
|
switch (_b.label) {
|
|
257
320
|
case 0:
|
|
258
321
|
_b.trys.push([0, 2, , 3]);
|
|
259
|
-
return [4 /*yield*/,
|
|
260
|
-
case 1: return [2 /*return*/, _b.sent()];
|
|
322
|
+
return [4 /*yield*/, loadMobileMetaForInit()];
|
|
323
|
+
case 1: return [2 /*return*/, (_b.sent()).sessionAttributes];
|
|
261
324
|
case 2:
|
|
262
325
|
_a = _b.sent();
|
|
263
326
|
return [2 /*return*/, minimalSessionDeviceAttributes()];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionAttributes.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionAttributes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\nimport DeviceInfo from 'react-native-device-info';\n\n/**\n * Session attributes for React Native\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes match Flutter SDK format, with additional mobile-specific\n * monitoring fields (memory, device type, battery, etc.)\n *\n * SDK name, core version, and npm adapter are on Faro meta `sdk` (`getSdkMeta` in `metas/sdk.ts`).\n *\n * `react_native_version` is the host app's React Native **framework** version from `Platform`, not the Faro package.\n */\nexport interface SessionAttributes {\n /** Host app's React Native framework version (e.g. \"0.75.1\") from `Platform.constants`. */\n react_native_version: string;\n\n /** Operating system (\"iOS\" or \"Android\") */\n device_os?: string;\n\n /** OS version (e.g., \"17.0\" for iOS, \"15\" for Android) */\n device_os_version?: string;\n\n /** Detailed OS info (e.g., \"iOS 17.0\" or \"Android 15 (SDK 35)\") */\n device_os_detail?: string;\n\n /** Device manufacturer (e.g., \"apple\", \"samsung\") */\n device_manufacturer?: string;\n\n /** Raw model identifier (e.g., \"iPhone16,1\", \"SM-A155F\") */\n device_model?: string;\n\n /** Human-readable model name (e.g., \"iPhone 15 Pro\") */\n device_model_name?: string;\n\n /** Device brand (e.g., \"iPhone\", \"samsung\") */\n device_brand?: string;\n\n /** Whether device is physical or emulator (\"true\" or \"false\") */\n device_is_physical?: string;\n\n /** Unique device ID (UUID) */\n device_id?: string;\n\n /** Device type (\"mobile\" or \"tablet\") */\n device_type?: string;\n\n /** Total device memory in bytes */\n device_memory_total?: string;\n\n /** Currently used memory in bytes */\n device_memory_used?: string;\n\n /** Battery level percentage (e.g., \"85\") - empty if unavailable */\n device_battery_level?: string;\n\n /** Whether device is charging (\"true\" or \"false\") - empty if unavailable */\n device_is_charging?: string;\n\n /** Whether low power mode is enabled (\"true\" or \"false\") - empty if unavailable */\n device_low_power_mode?: string;\n\n /** Mobile carrier name (e.g., \"Verizon\") - empty if unavailable */\n device_carrier?: string;\n}\n\n/**\n * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.\n */\nfunction getReactNativeVersion(): string {\n try {\n const version = Platform.constants.reactNativeVersion;\n if (version && typeof version === 'object') {\n const { major, minor, patch, prerelease } = version as {\n major: number;\n minor: number;\n patch: number;\n prerelease?: number;\n };\n let versionString = `${major}.${minor}.${patch}`;\n if (prerelease) {\n versionString += `-rc.${prerelease}`;\n }\n return versionString;\n }\n return 'unknown';\n } catch (_error) {\n return 'unknown';\n }\n}\n\n/**\n * Get device ID using react-native-device-info\n * Returns unique device identifier or 'unknown' on error\n */\nasync function getDeviceId(): Promise<string> {\n try {\n // getUniqueId returns a UUID that persists across app installations\n return await DeviceInfo.getUniqueId();\n } catch (_error) {\n return 'unknown';\n }\n}\n\n/**\n * Get OS detail string matching Flutter SDK format\n * iOS: \"iOS 17.0\"\n * Android: \"Android 15 (SDK 35)\"\n */\nasync function getDeviceOsDetail(): Promise<string> {\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n\n if (Platform.OS === 'android') {\n try {\n const apiLevel = await DeviceInfo.getApiLevel();\n return `${systemName} ${systemVersion} (SDK ${apiLevel})`;\n } catch (_error) {\n return `${systemName} ${systemVersion}`;\n }\n }\n\n return `${systemName} ${systemVersion}`;\n}\n\n/**\n * Session attributes without device props when async collection or DeviceInfo is unavailable.\n * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.\n */\nexport function minimalSessionDeviceAttributes(): SessionAttributes {\n return {\n react_native_version: getReactNativeVersion(),\n };\n}\n\n/**\n * Get all session attributes\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes matching Flutter SDK:\n * - react_native_version (RN framework in the host app)\n * - device_os, device_os_version, device_os_detail\n * - device_manufacturer, device_model, device_model_name\n * - device_brand, device_is_physical, device_id\n *\n * Additional monitoring attributes:\n * - device_type (mobile/tablet)\n * - device_memory_total, device_memory_used\n * - device_battery_level, device_is_charging, device_low_power_mode\n * - device_carrier\n */\nexport async function getSessionAttributes(): Promise<SessionAttributes> {\n try {\n // Get device ID asynchronously\n const deviceId = await getDeviceId();\n const deviceOsDetail = await getDeviceOsDetail();\n\n // Get synchronous device info\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n const manufacturer = DeviceInfo.getManufacturerSync();\n const model = DeviceInfo.getModel();\n const deviceName = DeviceInfo.getDeviceNameSync();\n const brand = DeviceInfo.getBrand();\n const isEmulator = DeviceInfo.isEmulatorSync();\n const isTablet = DeviceInfo.isTablet();\n\n // Memory info\n const totalMemory = DeviceInfo.getTotalMemorySync();\n const usedMemory = DeviceInfo.getUsedMemorySync();\n const reactNativeVersion = getReactNativeVersion();\n\n // Try to get async device info (battery, carrier)\n let batteryLevel: string | undefined;\n let isCharging: string | undefined;\n let lowPowerMode: string | undefined;\n let carrier: string | undefined;\n\n try {\n const battery = await DeviceInfo.getBatteryLevel();\n if (battery >= 0) {\n batteryLevel = String(Math.round(battery * 100));\n }\n } catch (_error) {\n // Battery info not available\n }\n\n try {\n isCharging = String(await DeviceInfo.isBatteryCharging());\n } catch (_error) {\n // Charging status not available\n }\n\n try {\n if ('isPowerSaveMode' in DeviceInfo) {\n lowPowerMode = String(\n await (DeviceInfo as typeof DeviceInfo & { isPowerSaveMode: () => Promise<boolean> }).isPowerSaveMode()\n );\n }\n } catch (_error) {\n // Low power mode not available\n }\n\n try {\n const carrierName = await DeviceInfo.getCarrier();\n if (carrierName && carrierName !== 'unknown') {\n carrier = carrierName;\n }\n } catch (_error) {\n // Carrier not available\n }\n\n const attributes: SessionAttributes = {\n react_native_version: reactNativeVersion,\n device_os: systemName,\n device_os_version: systemVersion,\n device_os_detail: deviceOsDetail,\n device_manufacturer: manufacturer.toLowerCase(),\n device_model: model,\n device_model_name: deviceName,\n device_brand: brand,\n device_is_physical: String(!isEmulator),\n device_id: deviceId,\n device_type: isTablet ? 'tablet' : 'mobile',\n device_memory_total: String(totalMemory),\n device_memory_used: String(usedMemory),\n device_battery_level: batteryLevel,\n device_is_charging: isCharging,\n device_low_power_mode: lowPowerMode,\n device_carrier: carrier,\n };\n\n return attributes;\n } catch (_error) {\n return minimalSessionDeviceAttributes();\n }\n}\n\n/**\n * Await full async session device attributes (battery, carrier, etc.), then fall back to\n * {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.\n */\nexport async function loadSessionDeviceAttributesForInit(): Promise<SessionAttributes> {\n try {\n return await getSessionAttributes();\n } catch {\n return minimalSessionDeviceAttributes();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sessionAttributes.js","sourceRoot":"","sources":["../../../../src/instrumentations/session/sessionAttributes.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+KA,wEAIC;AAkBD,oDAEC;AA8HD,sDAEC;AAMD,gFAMC;AAnVD,6CAAwC;AACxC,sFAAkD;AAIlD,mDAAqD;AAuErD;;GAEG;AACH,SAAS,qBAAqB;IAC5B,IAAI,CAAC;QACH,IAAM,OAAO,GAAG,uBAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC;QACtD,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAA,KAAsC,OAK3C,EALO,KAAK,WAAA,EAAE,KAAK,WAAA,EAAE,KAAK,WAAA,EAAE,UAAU,gBAKtC,CAAC;YACF,IAAI,aAAa,GAAG,UAAG,KAAK,cAAI,KAAK,cAAI,KAAK,CAAE,CAAC;YACjD,IAAI,UAAU,EAAE,CAAC;gBACf,aAAa,IAAI,cAAO,UAAU,CAAE,CAAC;YACvC,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAa,EAAE,KAAa;IAC5D,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClE,CAAC;AAED,SAAS,+BAA+B,CAAC,YAAoB;IAC3D,OAAO,uBAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;AAC3E,CAAC;AAED,SAAS,kCAAkC,CAAC,KAAa;IACvD,8EAA8E;IAC9E,oBAAoB;IACpB,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wEAAwE;IACxE,uEAAuE;IACvE,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,kCAAU,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAiB;IAC5C,2EAA2E;IAC3E,gEAAgE;IAChE,IAAI,uBAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAe,iBAAiB;;;;;;oBACxB,UAAU,GAAG,kCAAU,CAAC,aAAa,EAAE,CAAC;oBACxC,aAAa,GAAG,kCAAU,CAAC,gBAAgB,EAAE,CAAC;yBAEhD,CAAA,uBAAQ,CAAC,EAAE,KAAK,SAAS,CAAA,EAAzB,wBAAyB;;;;oBAER,qBAAM,kCAAU,CAAC,WAAW,EAAE,EAAA;;oBAAzC,QAAQ,GAAG,SAA8B;oBAC/C,sBAAO,UAAG,UAAU,cAAI,aAAa,mBAAS,QAAQ,MAAG,EAAC;;;oBAE1D,sBAAO,UAAG,UAAU,cAAI,aAAa,CAAE,EAAC;wBAI5C,sBAAO,UAAG,UAAU,cAAI,aAAa,CAAE,EAAC;;;;CACzC;AAED,SAAe,kBAAkB;;;;;;;oBAIb,qBAAM,kCAAU,CAAC,UAAU,EAAE,EAAA;;oBAAvC,OAAO,GAAG,SAA6B;oBAC7C,sBAAO,OAAO,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAC;;;oBAE9D,sBAAO,SAAS,EAAC;;;;;CAEpB;AAED;;;GAGG;AACH,SAAgB,8BAA8B;IAC5C,OAAO;QACL,oBAAoB,EAAE,qBAAqB,EAAE;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAsB,oBAAoB;;;;wBAChC,qBAAM,iBAAiB,EAAE,EAAA;wBAAjC,sBAAO,CAAC,SAAyB,CAAC,CAAC,iBAAiB,EAAC;;;;CACtD;AAED,SAAe,iBAAiB;;;;;;;oBAE8B,qBAAM,OAAO,CAAC,GAAG,CAAC;4BAC1E,iBAAiB,EAAE;4BACnB,kBAAkB,EAAE;4BACpB,IAAA,kCAAiB,GAAE;yBACpB,CAAC,EAAA;;oBAJI,KAAoD,SAIxD,EAJK,cAAc,QAAA,EAAE,eAAe,QAAA,EAAE,cAAc,QAAA;oBAOhD,UAAU,GAAG,kCAAU,CAAC,aAAa,EAAE,CAAC;oBACxC,aAAa,GAAG,kCAAU,CAAC,gBAAgB,EAAE,CAAC;oBAC9C,YAAY,GAAG,kCAAU,CAAC,mBAAmB,EAAE,CAAC;oBAChD,KAAK,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBAC9B,eAAe,GAAG,kCAAkC,CAAC,KAAK,CAAC,CAAC;oBAC5D,UAAU,GAAG,kCAAU,CAAC,iBAAiB,EAAE,CAAC;oBAC5C,KAAK,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBAC9B,UAAU,GAAG,kCAAU,CAAC,cAAc,EAAE,CAAC;oBACzC,QAAQ,GAAG,kCAAU,CAAC,QAAQ,EAAE,CAAC;oBACjC,UAAU,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;oBAG3C,WAAW,GAAG,kCAAU,CAAC,kBAAkB,EAAE,CAAC;oBAC9C,UAAU,GAAG,kCAAU,CAAC,iBAAiB,EAAE,CAAC;oBAC5C,kBAAkB,GAAG,qBAAqB,EAAE,CAAC;oBAG/C,YAAY,SAAoB,CAAC;oBACjC,UAAU,SAAoB,CAAC;oBAC/B,YAAY,SAAoB,CAAC;oBACjC,OAAO,SAAoB,CAAC;;;;oBAGd,qBAAM,kCAAU,CAAC,eAAe,EAAE,EAAA;;oBAA5C,OAAO,GAAG,SAAkC;oBAClD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;wBACjB,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC;oBACnD,CAAC;;;;;;;oBAMY,KAAA,MAAM,CAAA;oBAAC,qBAAM,kCAAU,CAAC,iBAAiB,EAAE,EAAA;;oBAAxD,UAAU,GAAG,kBAAO,SAAoC,EAAC,CAAC;;;;;;;yBAMtD,CAAA,iBAAiB,IAAI,kCAAU,CAAA,EAA/B,yBAA+B;oBAClB,KAAA,MAAM,CAAA;oBACnB,qBAAO,kCAA8E,CAAC,eAAe,EAAE,EAAA;;oBADzG,YAAY,GAAG,kBACb,SAAuG,EACxG,CAAC;;;;;;;;oBAOgB,qBAAM,kCAAU,CAAC,UAAU,EAAE,EAAA;;oBAA3C,WAAW,GAAG,SAA6B;oBACjD,IAAI,WAAW,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;wBAC7C,OAAO,GAAG,WAAW,CAAC;oBACxB,CAAC;;;;;;oBAKG,UAAU,gCACd,oBAAoB,EAAE,kBAAkB,EACxC,SAAS,EAAE,UAAU,EACrB,iBAAiB,EAAE,aAAa,EAChC,gBAAgB,EAAE,cAAc,EAChC,mBAAmB,EAAE,YAAY,CAAC,WAAW,EAAE,EAC/C,YAAY,EAAE,KAAK,EACnB,iBAAiB,EAAE,UAAU,EAC7B,YAAY,EAAE,KAAK,EACnB,kBAAkB,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IACpC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACrD,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClD,mBAAmB,EAAE,MAAM,CAAC,WAAW,CAAC,EACxC,kBAAkB,EAAE,MAAM,CAAC,UAAU,CAAC,EACtC,oBAAoB,EAAE,YAAY,EAClC,kBAAkB,EAAE,UAAU,EAC9B,qBAAqB,EAAE,YAAY,EACnC,cAAc,EAAE,OAAO,GACxB,CAAC;oBACI,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,gBAAA,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACnD,qBAAqB,GAAG,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;oBAC/D,4BAA4B,GAAG,+BAA+B,CAAC,YAAY,CAAC,CAAC;oBAC7E,MAAM,yBACP,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACzD,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,aAAa,GACvB,CAAC;oBAEF,sBAAO;4BACL,iBAAiB,EAAE,UAAU;4BAC7B,IAAI,EAAE;gCACJ,GAAG,EAAE,OAAO;gCACZ,MAAM,+BACJ,KAAK,EAAE,qBAAqB,EAC5B,WAAW,EAAE,CAAC,UAAU,EACxB,YAAY,EAAE,4BAA4B,IACvC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACjE,UAAU,EAAE,KAAK,KACd,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5C;gCACD,EAAE,EAAE,MAAM;6BACX;yBACF,EAAC;;;oBAEqB,qBAAM,IAAA,kCAAiB,GAAE,EAAA;;oBAA1C,cAAc,GAAG,SAAyB;oBAEhD,sBAAO;4BACL,iBAAiB,EAAE,8BAA8B,EAAE;4BACnD,IAAI,EAAE;gCACJ,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,gBAAA,EAAE,CAAC,CAAC,CAAC,EAAE;6BAC9C;yBACF,EAAC;;;;;CAEL;AAED;;GAEG;AACH,SAAsB,qBAAqB;;;YACzC,sBAAO,iBAAiB,EAAE,EAAC;;;CAC5B;AAED;;;GAGG;AACH,SAAsB,kCAAkC;;;;;;;oBAE5C,qBAAM,qBAAqB,EAAE,EAAA;wBAArC,sBAAO,CAAC,SAA6B,CAAC,CAAC,iBAAiB,EAAC;;;oBAEzD,sBAAO,8BAA8B,EAAE,EAAC;;;;;CAE3C","sourcesContent":["import { Platform } from 'react-native';\nimport DeviceInfo from 'react-native-device-info';\n\nimport type { Meta } from '@grafana/faro-core';\n\nimport { getInstallationId } from './installationId';\n\n/**\n * Session attributes for React Native\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes match Flutter SDK format, with additional mobile-specific\n * monitoring fields (memory, device type, battery, etc.)\n *\n * SDK name, core version, and npm adapter are on Faro meta `sdk` (`getSdkMeta` in `metas/sdk.ts`).\n *\n * `react_native_version` is the host app's React Native **framework** version from `Platform`, not the Faro package.\n */\nexport interface SessionAttributes {\n /** Host app's React Native framework version (e.g. \"0.75.1\") from `Platform.constants`. */\n react_native_version: string;\n\n /** Operating system (\"iOS\" or \"Android\") */\n device_os?: string;\n\n /** OS version (e.g., \"17.0\" for iOS, \"15\" for Android) */\n device_os_version?: string;\n\n /** Detailed OS info (e.g., \"iOS 17.0\" or \"Android 15 (SDK 35)\") */\n device_os_detail?: string;\n\n /** Device manufacturer (e.g., \"apple\", \"samsung\", \"Google\") */\n device_manufacturer?: string;\n\n /** Device model in flat session attributes (e.g., \"iPhone 15 Pro\", \"SM-A155F\") */\n device_model?: string;\n\n /** Human-readable model name (e.g., \"iPhone 15 Pro\") */\n device_model_name?: string;\n\n /** Device brand in flat session attributes (e.g., \"Apple\", \"samsung\") */\n device_brand?: string;\n\n /** Whether device is physical or emulator (\"true\" or \"false\") */\n device_is_physical?: string;\n\n /** Temporary flat attribute mirroring `app.installationId` during migration. */\n device_id?: string;\n\n /** Device type (\"mobile\" or \"tablet\") */\n device_type?: string;\n\n /** Total device memory in bytes */\n device_memory_total?: string;\n\n /** Currently used memory in bytes */\n device_memory_used?: string;\n\n /** Battery level percentage (e.g., \"85\") - empty if unavailable */\n device_battery_level?: string;\n\n /** Whether device is charging (\"true\" or \"false\") - empty if unavailable */\n device_is_charging?: string;\n\n /** Whether low power mode is enabled (\"true\" or \"false\") - empty if unavailable */\n device_low_power_mode?: string;\n\n /** Mobile carrier name (e.g., \"Verizon\") - empty if unavailable */\n device_carrier?: string;\n}\n\nexport interface PreloadedMobileMeta {\n sessionAttributes: SessionAttributes;\n meta: Pick<Meta, 'app' | 'device' | 'os'>;\n}\n\n/**\n * React Native framework version from `Platform.constants` (host app runtime), not `@grafana/faro-react-native` semver.\n */\nfunction getReactNativeVersion(): string {\n try {\n const version = Platform.constants.reactNativeVersion;\n if (version && typeof version === 'object') {\n const { major, minor, patch, prerelease } = version as {\n major: number;\n minor: number;\n patch: number;\n prerelease?: number;\n };\n let versionString = `${major}.${minor}.${patch}`;\n if (prerelease) {\n versionString += `-rc.${prerelease}`;\n }\n return versionString;\n }\n return 'unknown';\n } catch (_error) {\n return 'unknown';\n }\n}\n\nfunction getStructuredDeviceBrand(model: string, brand: string): string {\n if (Platform.OS !== 'ios') {\n return brand;\n }\n\n return model.toLowerCase().includes('ipad') ? 'iPad' : 'iPhone';\n}\n\nfunction getStructuredDeviceManufacturer(manufacturer: string): string {\n return Platform.OS === 'ios' ? manufacturer.toLowerCase() : manufacturer;\n}\n\nfunction getStructuredDeviceModelIdentifier(model: string): string | undefined {\n // Android getDeviceId() returns a board code, so use Build.MODEL for the Faro\n // model identifier.\n if (Platform.OS === 'android') {\n return model;\n }\n\n // React Native reports iPhone and iPadOS apps as Platform.OS === 'ios'.\n // react-native-device-info exposes the Apple hardware identifier here.\n if (Platform.OS === 'ios') {\n return DeviceInfo.getDeviceId();\n }\n\n return undefined;\n}\n\nfunction getMobileDeviceType(isTablet: boolean): 'mobile' | 'tablet' | undefined {\n // iPadOS is still reported as Platform.OS === 'ios'; DeviceInfo.isTablet()\n // distinguishes iPad/tablet form factor from phone form factor.\n if (Platform.OS === 'ios' || Platform.OS === 'android') {\n return isTablet ? 'tablet' : 'mobile';\n }\n\n return undefined;\n}\n\n/**\n * Get OS detail string matching Flutter SDK format\n * iOS: \"iOS 17.0\"\n * Android: \"Android 15 (SDK 35)\"\n */\nasync function getDeviceOsDetail(): Promise<string> {\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n\n if (Platform.OS === 'android') {\n try {\n const apiLevel = await DeviceInfo.getApiLevel();\n return `${systemName} ${systemVersion} (SDK ${apiLevel})`;\n } catch (_error) {\n return `${systemName} ${systemVersion}`;\n }\n }\n\n return `${systemName} ${systemVersion}`;\n}\n\nasync function getDeviceOsBuildId(): Promise<string | undefined> {\n try {\n // RN device-info exposes a useful OS build id on both Android and iOS.\n // Keep it omitted when unavailable instead of sending \"unknown\".\n const buildId = await DeviceInfo.getBuildId();\n return buildId && buildId !== 'unknown' ? buildId : undefined;\n } catch (_error) {\n return undefined;\n }\n}\n\n/**\n * Session attributes without device props when async collection or DeviceInfo is unavailable.\n * No synchronous DeviceInfo reads — use {@link getSessionAttributes} or the package async `initializeFaro`.\n */\nexport function minimalSessionDeviceAttributes(): SessionAttributes {\n return {\n react_native_version: getReactNativeVersion(),\n };\n}\n\n/**\n * Get all session attributes\n * These attributes are automatically included with every telemetry event\n *\n * Core attributes matching Flutter SDK:\n * - react_native_version (RN framework in the host app)\n * - device_os, device_os_version, device_os_detail\n * - device_manufacturer, device_model, device_model_name\n * - device_brand, device_is_physical, device_id\n *\n * Additional monitoring attributes:\n * - device_type (mobile/tablet)\n * - device_memory_total, device_memory_used\n * - device_battery_level, device_is_charging, device_low_power_mode\n * - device_carrier\n */\nexport async function getSessionAttributes(): Promise<SessionAttributes> {\n return (await collectMobileMeta()).sessionAttributes;\n}\n\nasync function collectMobileMeta(): Promise<PreloadedMobileMeta> {\n try {\n const [deviceOsDetail, deviceOsBuildId, installationId] = await Promise.all([\n getDeviceOsDetail(),\n getDeviceOsBuildId(),\n getInstallationId(),\n ]);\n\n // Get synchronous device info\n const systemName = DeviceInfo.getSystemName();\n const systemVersion = DeviceInfo.getSystemVersion();\n const manufacturer = DeviceInfo.getManufacturerSync();\n const model = DeviceInfo.getModel();\n const modelIdentifier = getStructuredDeviceModelIdentifier(model);\n const deviceName = DeviceInfo.getDeviceNameSync();\n const brand = DeviceInfo.getBrand();\n const isEmulator = DeviceInfo.isEmulatorSync();\n const isTablet = DeviceInfo.isTablet();\n const deviceType = getMobileDeviceType(isTablet);\n\n // Memory info\n const totalMemory = DeviceInfo.getTotalMemorySync();\n const usedMemory = DeviceInfo.getUsedMemorySync();\n const reactNativeVersion = getReactNativeVersion();\n\n // Try to get async device info (battery, carrier)\n let batteryLevel: string | undefined;\n let isCharging: string | undefined;\n let lowPowerMode: string | undefined;\n let carrier: string | undefined;\n\n try {\n const battery = await DeviceInfo.getBatteryLevel();\n if (battery >= 0) {\n batteryLevel = String(Math.round(battery * 100));\n }\n } catch (_error) {\n // Battery info not available\n }\n\n try {\n isCharging = String(await DeviceInfo.isBatteryCharging());\n } catch (_error) {\n // Charging status not available\n }\n\n try {\n if ('isPowerSaveMode' in DeviceInfo) {\n lowPowerMode = String(\n await (DeviceInfo as typeof DeviceInfo & { isPowerSaveMode: () => Promise<boolean> }).isPowerSaveMode()\n );\n }\n } catch (_error) {\n // Low power mode not available\n }\n\n try {\n const carrierName = await DeviceInfo.getCarrier();\n if (carrierName && carrierName !== 'unknown') {\n carrier = carrierName;\n }\n } catch (_error) {\n // Carrier not available\n }\n\n const attributes: SessionAttributes = {\n react_native_version: reactNativeVersion,\n device_os: systemName,\n device_os_version: systemVersion,\n device_os_detail: deviceOsDetail,\n device_manufacturer: manufacturer.toLowerCase(),\n device_model: model,\n device_model_name: deviceName,\n device_brand: brand,\n device_is_physical: String(!isEmulator),\n ...(installationId ? { device_id: installationId } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n device_memory_total: String(totalMemory),\n device_memory_used: String(usedMemory),\n device_battery_level: batteryLevel,\n device_is_charging: isCharging,\n device_low_power_mode: lowPowerMode,\n device_carrier: carrier,\n };\n const appMeta = installationId ? { installationId } : {};\n const structuredDeviceBrand = getStructuredDeviceBrand(model, brand);\n const structuredDeviceManufacturer = getStructuredDeviceManufacturer(manufacturer);\n const osMeta = {\n ...(deviceOsBuildId ? { build_id: deviceOsBuildId } : {}),\n detail: deviceOsDetail,\n name: systemName,\n version: systemVersion,\n };\n\n return {\n sessionAttributes: attributes,\n meta: {\n app: appMeta,\n device: {\n brand: structuredDeviceBrand,\n is_physical: !isEmulator,\n manufacturer: structuredDeviceManufacturer,\n ...(modelIdentifier ? { model_identifier: modelIdentifier } : {}),\n model_name: model,\n ...(deviceType ? { type: deviceType } : {}),\n },\n os: osMeta,\n },\n };\n } catch (_error) {\n const installationId = await getInstallationId();\n\n return {\n sessionAttributes: minimalSessionDeviceAttributes(),\n meta: {\n app: installationId ? { installationId } : {},\n },\n };\n }\n}\n\n/**\n * Get structured mobile meta plus flat session attributes for async `initializeFaro`.\n */\nexport async function loadMobileMetaForInit(): Promise<PreloadedMobileMeta> {\n return collectMobileMeta();\n}\n\n/**\n * Await full async session device attributes (battery, carrier, etc.), then fall back to\n * {@link minimalSessionDeviceAttributes} if anything throws. Used by async `initializeFaro`.\n */\nexport async function loadSessionDeviceAttributesForInit(): Promise<SessionAttributes> {\n try {\n return (await loadMobileMetaForInit()).sessionAttributes;\n } catch {\n return minimalSessionDeviceAttributes();\n }\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.getMetroInjectedBundleId = getMetroInjectedBundleId;
|
|
43
|
+
exports.formatSymbolsBundleId = formatSymbolsBundleId;
|
|
44
|
+
exports.loadAppSymbolsBundleIdForInit = loadAppSymbolsBundleIdForInit;
|
|
45
|
+
var react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
46
|
+
var faro_core_1 = require("@grafana/faro-core");
|
|
47
|
+
var BUNDLE_ID_SEPARATOR = '@';
|
|
48
|
+
/** Metro / webpack preamble bundle id for JS source maps (`__faroBundleId_<appName>`). */
|
|
49
|
+
function getMetroInjectedBundleId(appName) {
|
|
50
|
+
if (!appName) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
var key = "__faroBundleId_".concat(appName);
|
|
54
|
+
var fromGlobal = faro_core_1.globalObject[key];
|
|
55
|
+
if (typeof fromGlobal === 'string' && fromGlobal !== '') {
|
|
56
|
+
return fromGlobal;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Encodes the Android/iOS build identity used as `meta.app.bundleId` for
|
|
62
|
+
* server-side symbol retrace. Must match the symbols upload bundle id
|
|
63
|
+
* (`{applicationId}@{versionCode}@{versionName}`).
|
|
64
|
+
*/
|
|
65
|
+
function formatSymbolsBundleId(applicationId, versionCode, versionName) {
|
|
66
|
+
return "".concat(applicationId).concat(BUNDLE_ID_SEPARATOR).concat(versionCode).concat(BUNDLE_ID_SEPARATOR).concat(versionName);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Reads the installed build's identity from `react-native-device-info` and
|
|
70
|
+
* returns the encoded bundle id when all parts are available.
|
|
71
|
+
*
|
|
72
|
+
* Values must match what the symbol uploader (Gradle plugin / faro-cli) sends
|
|
73
|
+
* for the same build so the collector can locate the mapping for retrace.
|
|
74
|
+
*/
|
|
75
|
+
function loadAppSymbolsBundleIdForInit() {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
77
|
+
var applicationId, versionName, versionCodeRaw;
|
|
78
|
+
return __generator(this, function (_a) {
|
|
79
|
+
try {
|
|
80
|
+
applicationId = react_native_device_info_1.default.getBundleId();
|
|
81
|
+
versionName = react_native_device_info_1.default.getVersion();
|
|
82
|
+
versionCodeRaw = react_native_device_info_1.default.getBuildNumber();
|
|
83
|
+
if (!applicationId || versionCodeRaw === '' || versionCodeRaw == null || !versionName) {
|
|
84
|
+
return [2 /*return*/, undefined];
|
|
85
|
+
}
|
|
86
|
+
return [2 /*return*/, formatSymbolsBundleId(applicationId, String(versionCodeRaw), versionName)];
|
|
87
|
+
}
|
|
88
|
+
catch (_b) {
|
|
89
|
+
return [2 /*return*/, undefined];
|
|
90
|
+
}
|
|
91
|
+
return [2 /*return*/];
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=appBuildIdentity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appBuildIdentity.js","sourceRoot":"","sources":["../../../src/metas/appBuildIdentity.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,4DAUC;AAOD,sDAEC;AASD,sEAcC;AAjDD,sFAAkD;AAElD,gDAAkD;AAElD,IAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,0FAA0F;AAC1F,SAAgB,wBAAwB,CAAC,OAA2B;IAClE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAM,GAAG,GAAG,yBAAkB,OAAO,CAAE,CAAC;IACxC,IAAM,UAAU,GAAI,wBAAwC,CAAC,GAAG,CAAC,CAAC;IAClE,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACxD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CAAC,aAAqB,EAAE,WAAmB,EAAE,WAAmB;IACnG,OAAO,UAAG,aAAa,SAAG,mBAAmB,SAAG,WAAW,SAAG,mBAAmB,SAAG,WAAW,CAAE,CAAC;AACpG,CAAC;AAED;;;;;;GAMG;AACH,SAAsB,6BAA6B;;;;YACjD,IAAI,CAAC;gBACG,aAAa,GAAG,kCAAU,CAAC,WAAW,EAAE,CAAC;gBACzC,WAAW,GAAG,kCAAU,CAAC,UAAU,EAAE,CAAC;gBACtC,cAAc,GAAG,kCAAU,CAAC,cAAc,EAAE,CAAC;gBAEnD,IAAI,CAAC,aAAa,IAAI,cAAc,KAAK,EAAE,IAAI,cAAc,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACtF,sBAAO,SAAS,EAAC;gBACnB,CAAC;gBAED,sBAAO,qBAAqB,CAAC,aAAa,EAAE,MAAM,CAAC,cAAc,CAAC,EAAE,WAAW,CAAC,EAAC;YACnF,CAAC;YAAC,WAAM,CAAC;gBACP,sBAAO,SAAS,EAAC;YACnB,CAAC;;;;CACF","sourcesContent":["import DeviceInfo from 'react-native-device-info';\n\nimport { globalObject } from '@grafana/faro-core';\n\nconst BUNDLE_ID_SEPARATOR = '@';\n\n/** Metro / webpack preamble bundle id for JS source maps (`__faroBundleId_<appName>`). */\nexport function getMetroInjectedBundleId(appName: string | undefined): string | undefined {\n if (!appName) {\n return undefined;\n }\n const key = `__faroBundleId_${appName}`;\n const fromGlobal = (globalObject as Record<string, unknown>)[key];\n if (typeof fromGlobal === 'string' && fromGlobal !== '') {\n return fromGlobal;\n }\n return undefined;\n}\n\n/**\n * Encodes the Android/iOS build identity used as `meta.app.bundleId` for\n * server-side symbol retrace. Must match the symbols upload bundle id\n * (`{applicationId}@{versionCode}@{versionName}`).\n */\nexport function formatSymbolsBundleId(applicationId: string, versionCode: string, versionName: string): string {\n return `${applicationId}${BUNDLE_ID_SEPARATOR}${versionCode}${BUNDLE_ID_SEPARATOR}${versionName}`;\n}\n\n/**\n * Reads the installed build's identity from `react-native-device-info` and\n * returns the encoded bundle id when all parts are available.\n *\n * Values must match what the symbol uploader (Gradle plugin / faro-cli) sends\n * for the same build so the collector can locate the mapping for retrace.\n */\nexport async function loadAppSymbolsBundleIdForInit(): Promise<string | undefined> {\n try {\n const applicationId = DeviceInfo.getBundleId();\n const versionName = DeviceInfo.getVersion();\n const versionCodeRaw = DeviceInfo.getBuildNumber();\n\n if (!applicationId || versionCodeRaw === '' || versionCodeRaw == null || !versionName) {\n return undefined;\n }\n\n return formatSymbolsBundleId(applicationId, String(versionCodeRaw), versionName);\n } catch {\n return undefined;\n }\n}\n"]}
|
|
@@ -9,10 +9,15 @@ function mockDeviceInfo() {
|
|
|
9
9
|
default: {
|
|
10
10
|
getBrand: jest.fn(function () { return 'Apple'; }),
|
|
11
11
|
getDeviceId: jest.fn(function () { return 'iPhone14,2'; }),
|
|
12
|
+
getDeviceNameSync: jest.fn(function () { return "Test's iPhone"; }),
|
|
13
|
+
getUniqueId: jest.fn(function () { return Promise.resolve('test-device-id'); }),
|
|
12
14
|
getModel: jest.fn(function () { return 'iPhone 13 Pro'; }),
|
|
15
|
+
getManufacturerSync: jest.fn(function () { return 'Apple'; }),
|
|
13
16
|
getSystemName: jest.fn(function () { return 'iOS'; }),
|
|
14
17
|
getSystemVersion: jest.fn(function () { return '16.0'; }),
|
|
15
18
|
getVersion: jest.fn(function () { return '1.0.0'; }),
|
|
19
|
+
getApiLevel: jest.fn(function () { return Promise.resolve(35); }),
|
|
20
|
+
getBuildId: jest.fn(function () { return Promise.resolve('22B83'); }),
|
|
16
21
|
isTablet: jest.fn(function () { return false; }),
|
|
17
22
|
isEmulatorSync: jest.fn(function () { return false; }),
|
|
18
23
|
getTotalMemorySync: jest.fn(function () { return 6442450944; }), // 6GB in bytes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockDeviceInfo.js","sourceRoot":"","sources":["../../../src/testUtils/mockDeviceInfo.ts"],"names":[],"mappings":";;AAGA,
|
|
1
|
+
{"version":3,"file":"mockDeviceInfo.js","sourceRoot":"","sources":["../../../src/testUtils/mockDeviceInfo.ts"],"names":[],"mappings":";;AAGA,wCAwBC;AA3BD;;GAEG;AACH,SAAgB,cAAc;IAC5B,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,cAAM,OAAA,CAAC;QAC3C,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAChC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,YAAY,EAAZ,CAAY,CAAC;YACxC,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,eAAe,EAAf,CAAe,CAAC;YACjD,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAjC,CAAiC,CAAC;YAC7D,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,eAAe,EAAf,CAAe,CAAC;YACxC,mBAAmB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAC3C,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACnC,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,MAAM,EAAN,CAAM,CAAC;YACvC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,EAAP,CAAO,CAAC;YAClC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAnB,CAAmB,CAAC;YAC/C,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAxB,CAAwB,CAAC;YACnD,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YAC9B,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,KAAK,EAAL,CAAK,CAAC;YACpC,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC9D,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,UAAU,EAAV,CAAU,CAAC,EAAE,eAAe;YAC7D,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAArB,CAAqB,CAAC;YACrD,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAA3B,CAA2B,CAAC;YACtD,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;YACtD,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAtB,CAAsB,CAAC;SACzD;KACF,CAAC,EAtB0C,CAsB1C,CAAC,CAAC;AACN,CAAC","sourcesContent":["/**\n * Mock react-native-device-info for testing\n */\nexport function mockDeviceInfo(): void {\n jest.mock('react-native-device-info', () => ({\n default: {\n getBrand: jest.fn(() => 'Apple'),\n getDeviceId: jest.fn(() => 'iPhone14,2'),\n getDeviceNameSync: jest.fn(() => \"Test's iPhone\"),\n getUniqueId: jest.fn(() => Promise.resolve('test-device-id')),\n getModel: jest.fn(() => 'iPhone 13 Pro'),\n getManufacturerSync: jest.fn(() => 'Apple'),\n getSystemName: jest.fn(() => 'iOS'),\n getSystemVersion: jest.fn(() => '16.0'),\n getVersion: jest.fn(() => '1.0.0'),\n getApiLevel: jest.fn(() => Promise.resolve(35)),\n getBuildId: jest.fn(() => Promise.resolve('22B83')),\n isTablet: jest.fn(() => false),\n isEmulatorSync: jest.fn(() => false),\n getTotalMemorySync: jest.fn(() => 6442450944), // 6GB in bytes\n getUsedMemorySync: jest.fn(() => 2147483648), // 2GB in bytes\n getBatteryLevel: jest.fn(() => Promise.resolve(0.75)),\n getCarrier: jest.fn(() => Promise.resolve('T-Mobile')),\n isPowerSaveMode: jest.fn(() => Promise.resolve(false)),\n isBatteryCharging: jest.fn(() => Promise.resolve(false)),\n },\n }));\n}\n"]}
|
|
@@ -19,10 +19,17 @@ jest.mock('react-native-device-info', function () {
|
|
|
19
19
|
var mockDeviceInfo = {
|
|
20
20
|
getBrand: jest.fn(function () { return 'Apple'; }),
|
|
21
21
|
getDeviceId: jest.fn(function () { return 'iPhone14,2'; }),
|
|
22
|
+
getDeviceNameSync: jest.fn(function () { return "Test's iPhone"; }),
|
|
23
|
+
getUniqueId: jest.fn(function () { return Promise.resolve('test-device-id'); }),
|
|
22
24
|
getModel: jest.fn(function () { return 'iPhone 13 Pro'; }),
|
|
25
|
+
getManufacturerSync: jest.fn(function () { return 'Apple'; }),
|
|
23
26
|
getSystemName: jest.fn(function () { return 'iOS'; }),
|
|
24
27
|
getSystemVersion: jest.fn(function () { return '16.0'; }),
|
|
25
28
|
getVersion: jest.fn(function () { return '1.0.0'; }),
|
|
29
|
+
getBundleId: jest.fn(function () { return 'com.example.myapp'; }),
|
|
30
|
+
getBuildNumber: jest.fn(function () { return '42'; }),
|
|
31
|
+
getApiLevel: jest.fn(function () { return Promise.resolve(35); }),
|
|
32
|
+
getBuildId: jest.fn(function () { return Promise.resolve('22B83'); }),
|
|
26
33
|
isTablet: jest.fn(function () { return false; }),
|
|
27
34
|
isEmulatorSync: jest.fn(function () { return false; }),
|
|
28
35
|
getTotalMemorySync: jest.fn(function () { return 6442450944; }), // 6GB in bytes
|