@grafana/faro-react-native 1.3.1 → 1.4.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/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/makeRNConfig.js +5 -5
- package/dist/cjs/config/makeRNConfig.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/makeRNConfig.js +5 -5
- package/dist/esm/config/makeRNConfig.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/makeRNConfig.ts +10 -9
- 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/initialize.test.ts +63 -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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/transports/fetch/index.ts"],"names":[],"mappings":";;;AAAA,yCAA6C;AAApC,2GAAA,cAAc,OAAA","sourcesContent":["export { FetchTransport } from './transport';\nexport type {
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/transports/fetch/index.ts"],"names":[],"mappings":";;;AAAA,yCAA6C;AAApC,2GAAA,cAAc,OAAA","sourcesContent":["export { FetchTransport } from './transport';\nexport type {\n FetchTransportOptions,\n FetchTransportRequestOptions,\n FetchTransportSendOutcome,\n FetchTransportSendResult,\n} from './types';\n"]}
|
|
@@ -81,7 +81,6 @@ var DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;
|
|
|
81
81
|
var MAX_CONSECUTIVE_FAILURES = 3;
|
|
82
82
|
var FAILURE_BACKOFF_MS = 30000; // 30 seconds
|
|
83
83
|
var TOO_MANY_REQUESTS = 429;
|
|
84
|
-
var ACCEPTED = 202;
|
|
85
84
|
var FetchTransport = /** @class */ (function (_super) {
|
|
86
85
|
__extends(FetchTransport, _super);
|
|
87
86
|
function FetchTransport(options) {
|
|
@@ -171,29 +170,51 @@ var FetchTransport = /** @class */ (function (_super) {
|
|
|
171
170
|
};
|
|
172
171
|
FetchTransport.prototype.send = function (items) {
|
|
173
172
|
return __awaiter(this, void 0, void 0, function () {
|
|
174
|
-
|
|
173
|
+
return __generator(this, function (_a) {
|
|
174
|
+
switch (_a.label) {
|
|
175
|
+
case 0: return [4 /*yield*/, this.sendWithResult(items)];
|
|
176
|
+
case 1:
|
|
177
|
+
_a.sent();
|
|
178
|
+
return [2 /*return*/];
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Sends a batch and reports whether the collector accepted it.
|
|
185
|
+
* The request header uses the live session for collector accounting. Payload
|
|
186
|
+
* metadata remains independent so delayed signals can retain their original
|
|
187
|
+
* session.
|
|
188
|
+
*/
|
|
189
|
+
FetchTransport.prototype.sendWithResult = function (items) {
|
|
190
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
191
|
+
var now, sessionId_1, response, _a;
|
|
175
192
|
var _this = this;
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
var _b;
|
|
194
|
+
return __generator(this, function (_c) {
|
|
195
|
+
switch (_c.label) {
|
|
178
196
|
case 0:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
197
|
+
this.logDebug("FetchTransport.sendWithResult() called with ".concat(items.length, " items"));
|
|
198
|
+
if (items.length === 0) {
|
|
199
|
+
return [2 /*return*/, { outcome: 'skipped' }];
|
|
200
|
+
}
|
|
201
|
+
_c.label = 1;
|
|
182
202
|
case 1:
|
|
183
|
-
|
|
203
|
+
_c.trys.push([1, 4, , 5]);
|
|
184
204
|
now = new Date(this.getNow());
|
|
185
205
|
// Check if we're in backoff period
|
|
186
206
|
if (this.disabledUntil > now) {
|
|
187
207
|
this.logDebug("FetchTransport: in backoff period until ".concat(this.disabledUntil));
|
|
188
|
-
return [2 /*return*/,
|
|
208
|
+
return [2 /*return*/, { outcome: 'skipped' }];
|
|
189
209
|
}
|
|
190
|
-
//
|
|
191
|
-
//
|
|
210
|
+
// The collector uses the header for session validation and accounting,
|
|
211
|
+
// independently of the session carried by each payload.
|
|
192
212
|
return [4 /*yield*/, this.waitForSession()];
|
|
193
213
|
case 2:
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
|
|
214
|
+
// The collector uses the header for session validation and accounting,
|
|
215
|
+
// independently of the session carried by each payload.
|
|
216
|
+
_c.sent();
|
|
217
|
+
sessionId_1 = (_b = this.metas.value.session) === null || _b === void 0 ? void 0 : _b.id;
|
|
197
218
|
return [4 /*yield*/, this.promiseBuffer.add(function () {
|
|
198
219
|
var transportBody = (0, faro_core_1.getTransportBody)(items);
|
|
199
220
|
var body = JSON.stringify(transportBody);
|
|
@@ -206,11 +227,6 @@ var FetchTransport = /** @class */ (function (_super) {
|
|
|
206
227
|
}
|
|
207
228
|
var _b = _this.options, url = _b.url, requestOptions = _b.requestOptions, apiKey = _b.apiKey;
|
|
208
229
|
var _c = requestOptions !== null && requestOptions !== void 0 ? requestOptions : {}, headers = _c.headers, restOfRequestOptions = __rest(_c, ["headers"]);
|
|
209
|
-
var sessionId;
|
|
210
|
-
var sessionMeta = _this.metas.value.session;
|
|
211
|
-
if (sessionMeta != null) {
|
|
212
|
-
sessionId = sessionMeta.id;
|
|
213
|
-
}
|
|
214
230
|
// DEBUG: Log fetch attempt
|
|
215
231
|
_this.logDebug("FetchTransport: sending ".concat(items.length, " items to ").concat(url));
|
|
216
232
|
// Create an AbortController for timeout
|
|
@@ -219,7 +235,7 @@ var FetchTransport = /** @class */ (function (_super) {
|
|
|
219
235
|
controller.abort();
|
|
220
236
|
_this.logDebug("FetchTransport: request timed out after 10s");
|
|
221
237
|
}, 10000);
|
|
222
|
-
return fetch(url, __assign({ method: 'POST', headers: __assign(__assign(__assign({ 'Content-Type': 'application/json' }, (headers !== null && headers !== void 0 ? headers : {})), (apiKey ? { 'x-api-key': apiKey } : {})), (
|
|
238
|
+
return fetch(url, __assign({ method: 'POST', headers: __assign(__assign(__assign({ 'Content-Type': 'application/json' }, (headers !== null && headers !== void 0 ? headers : {})), (apiKey ? { 'x-api-key': apiKey } : {})), (sessionId_1 ? { 'x-faro-session-id': sessionId_1 } : {})), body: body, signal: controller.signal }, (restOfRequestOptions !== null && restOfRequestOptions !== void 0 ? restOfRequestOptions : {})))
|
|
223
239
|
.then(function (response) { return __awaiter(_this, void 0, void 0, function () {
|
|
224
240
|
var text;
|
|
225
241
|
return __generator(this, function (_a) {
|
|
@@ -234,7 +250,7 @@ var FetchTransport = /** @class */ (function (_super) {
|
|
|
234
250
|
this.disabledUntil = this.getRetryAfterDate(response);
|
|
235
251
|
this.logDebug("FetchTransport: rate limited, disabled until ".concat(this.disabledUntil));
|
|
236
252
|
}
|
|
237
|
-
if (!(response.status
|
|
253
|
+
if (!(response.status < 200 || response.status >= 300)) return [3 /*break*/, 2];
|
|
238
254
|
return [4 /*yield*/, response.text().catch(function () { return ''; })];
|
|
239
255
|
case 1:
|
|
240
256
|
text = _a.sent();
|
|
@@ -259,14 +275,29 @@ var FetchTransport = /** @class */ (function (_super) {
|
|
|
259
275
|
}
|
|
260
276
|
// Do NOT log errors to console - this causes infinite loops in React Native
|
|
261
277
|
// when the DevTools console override intercepts even unpatchedConsole calls
|
|
278
|
+
return undefined;
|
|
262
279
|
});
|
|
263
280
|
})];
|
|
264
281
|
case 3:
|
|
265
|
-
|
|
266
|
-
|
|
282
|
+
response = _c.sent();
|
|
283
|
+
if (!response) {
|
|
284
|
+
return [2 /*return*/, { outcome: 'failed' }];
|
|
285
|
+
}
|
|
286
|
+
if (response.status >= 200 && response.status < 300) {
|
|
287
|
+
return [2 /*return*/, {
|
|
288
|
+
outcome: 'accepted',
|
|
289
|
+
status: response.status,
|
|
290
|
+
}];
|
|
291
|
+
}
|
|
292
|
+
return [2 /*return*/, {
|
|
293
|
+
outcome: 'rejected',
|
|
294
|
+
status: response.status,
|
|
295
|
+
}];
|
|
267
296
|
case 4:
|
|
268
|
-
_a =
|
|
269
|
-
|
|
297
|
+
_a = _c.sent();
|
|
298
|
+
// Buffer full error - Do NOT log to console as it creates infinite loops
|
|
299
|
+
// The error is typically "Task buffer full" when the device is offline
|
|
300
|
+
return [2 /*return*/, { outcome: 'failed' }];
|
|
270
301
|
case 5: return [2 /*return*/];
|
|
271
302
|
}
|
|
272
303
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseTransport, createPromiseBuffer, getTransportBody, VERSION } from '@grafana/faro-core';\nimport type { Patterns, PromiseBuffer, TransportItem } from '@grafana/faro-core';\n\nimport type { FetchTransportOptions } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5;\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\nconst MAX_CONSECUTIVE_FAILURES = 3;\nconst FAILURE_BACKOFF_MS = 30000; // 30 seconds\n\nconst TOO_MANY_REQUESTS = 429;\nconst ACCEPTED = 202;\n\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-react-native:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private disabledUntil: Date;\n private consecutiveFailures: number = 0;\n private sessionReadyPromise: Promise<void> | null = null;\n private sessionReadyResolve: (() => void) | null = null;\n private sessionReady: boolean = false;\n private metasListenerRegistered: boolean = false;\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n // Align with getNow so tests (and apps) that supply a clock do not see spurious backoff\n this.disabledUntil = new Date(this.getNow());\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n /**\n * Register a listener for metas changes to detect when session becomes available.\n * Uses faro-core's metas listener pattern instead of polling with setTimeout.\n */\n private registerSessionListener(): void {\n if (this.metasListenerRegistered || !this.metas?.addListener) {\n return;\n }\n\n this.metasListenerRegistered = true;\n\n this.metas.addListener((meta) => {\n if (meta.session?.id && this.sessionReadyResolve) {\n this.sessionReady = true;\n this.sessionReadyResolve();\n this.sessionReadyResolve = null;\n }\n });\n }\n\n /**\n * Wait for session to be available before sending.\n * This prevents 400 errors from the collector due to missing X-Faro-Session-Id header.\n *\n * Only waits if session tracking is enabled. If disabled, returns immediately.\n */\n private waitForSession(): Promise<void> {\n // Only wait for session if session tracking is enabled\n const sessionTrackingEnabled = this.config?.sessionTracking?.enabled;\n if (!sessionTrackingEnabled) {\n return Promise.resolve();\n }\n\n // Already have session\n if (this.sessionReady) {\n return Promise.resolve();\n }\n\n // Check if session is now available\n const sessionMeta = this.metas?.value?.session;\n if (sessionMeta?.id) {\n this.sessionReady = true;\n return Promise.resolve();\n }\n\n // Return existing promise if we're already waiting\n if (this.sessionReadyPromise) {\n return this.sessionReadyPromise;\n }\n\n // Register listener to be notified when session becomes available\n this.registerSessionListener();\n\n // Create a promise that resolves when session becomes available via listener\n this.sessionReadyPromise = new Promise<void>((resolve) => {\n this.sessionReadyResolve = resolve;\n\n // Also check immediately in case session was set between our check and listener registration\n const sessionMeta = this.metas?.value?.session;\n if (sessionMeta?.id) {\n this.sessionReady = true;\n resolve();\n this.sessionReadyResolve = null;\n }\n });\n\n return this.sessionReadyPromise;\n }\n\n async send(items: TransportItem[]): Promise<void> {\n // DEBUG: Log at the very start of send\n this.logDebug(`FetchTransport.send() called with ${items.length} items`);\n\n try {\n const now = new Date(this.getNow());\n\n // Check if we're in backoff period\n if (this.disabledUntil > now) {\n this.logDebug(`FetchTransport: in backoff period until ${this.disabledUntil}`);\n return Promise.resolve();\n }\n\n // Wait for session to be ready before sending\n // This prevents 400 errors from missing X-Faro-Session-Id header\n await this.waitForSession();\n\n await this.promiseBuffer.add(() => {\n const transportBody = getTransportBody(items);\n const body = JSON.stringify(transportBody);\n\n // DEBUG: Log measurement payloads to see what's being sent\n if (transportBody.measurements && transportBody.measurements.length > 0) {\n for (const m of transportBody.measurements) {\n this.logDebug(`FetchTransport: measurement payload - type=${m.type}, values=${JSON.stringify(m.values)}`);\n }\n }\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers, ...restOfRequestOptions } = requestOptions ?? {};\n\n let sessionId;\n const sessionMeta = this.metas.value.session;\n if (sessionMeta != null) {\n sessionId = sessionMeta.id;\n }\n\n // DEBUG: Log fetch attempt\n this.logDebug(`FetchTransport: sending ${items.length} items to ${url}`);\n\n // Create an AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n this.logDebug(`FetchTransport: request timed out after 10s`);\n }, 10000);\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(headers ?? {}),\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n signal: controller.signal,\n // Note: React Native doesn't support keepalive\n // keepalive: body.length <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then(async (response) => {\n clearTimeout(timeoutId);\n // DEBUG: Log response status\n this.logDebug(`FetchTransport: response status ${response.status}`);\n\n // Reset failure counter on success\n this.consecutiveFailures = 0;\n\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logDebug(`FetchTransport: rate limited, disabled until ${this.disabledUntil}`);\n }\n\n // Log non-success responses for debugging\n if (response.status !== ACCEPTED && response.status !== 200) {\n const text = await response.text().catch(() => '');\n this.logDebug(`FetchTransport: non-success response: ${response.status} ${text.slice(0, 200)}`);\n }\n\n return response;\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n // DEBUG: Log the error\n this.logDebug(`FetchTransport: fetch failed - ${error?.message || error}`);\n\n // Increment failure counter\n this.consecutiveFailures++;\n\n // After MAX_CONSECUTIVE_FAILURES, enable circuit breaker to prevent infinite loops\n if (this.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {\n this.disabledUntil = new Date(this.getNow() + FAILURE_BACKOFF_MS);\n // Reset counter so we can try again after backoff\n this.consecutiveFailures = 0;\n this.logDebug(`FetchTransport: circuit breaker activated, disabled for 30s`);\n }\n\n // Do NOT log errors to console - this causes infinite loops in React Native\n // when the DevTools console override intercepts even unpatchedConsole calls\n });\n });\n } catch {\n // Buffer full error - Do NOT log to console as it creates infinite loops\n // The error is typically \"Task buffer full\" when the device is offline\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAmG;AAKnG,IAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,IAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,IAAM,6BAA6B,GAAG,IAAI,CAAC;AAC3C,IAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,IAAM,kBAAkB,GAAG,KAAK,CAAC,CAAC,aAAa;AAE/C,IAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B;IAAoC,kCAAa;IAe/C,wBAAoB,OAA8B;;QAChD,YAAA,MAAK,WAAE,SAAC;QADU,aAAO,GAAP,OAAO,CAAuB;QAdzC,UAAI,GAAG,4CAA4C,CAAC;QACpD,aAAO,GAAG,mBAAO,CAAC;QAOnB,yBAAmB,GAAW,CAAC,CAAC;QAChC,yBAAmB,GAAyB,IAAI,CAAC;QACjD,yBAAmB,GAAwB,IAAI,CAAC;QAChD,kBAAY,GAAY,KAAK,CAAC;QAC9B,6BAAuB,GAAY,KAAK,CAAC;QAK/C,KAAI,CAAC,kBAAkB,GAAG,MAAA,OAAO,CAAC,yBAAyB,mCAAI,6BAA6B,CAAC;QAC7F,KAAI,CAAC,MAAM,GAAG,MAAA,OAAO,CAAC,MAAM,mCAAI,CAAC,cAAM,OAAA,IAAI,CAAC,GAAG,EAAE,EAAV,CAAU,CAAC,CAAC;QACnD,wFAAwF;QACxF,KAAI,CAAC,aAAa,GAAG,IAAI,IAAI,CAAC,KAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAE7C,KAAI,CAAC,aAAa,GAAG,IAAA,+BAAmB,EAAC;YACvC,IAAI,EAAE,MAAA,OAAO,CAAC,UAAU,mCAAI,mBAAmB;YAC/C,WAAW,EAAE,MAAA,OAAO,CAAC,WAAW,mCAAI,mBAAmB;SACxD,CAAC,CAAC;;IACL,CAAC;IAED;;;OAGG;IACK,gDAAuB,GAA/B;QAAA,iBAcC;;QAbC,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,CAAA,MAAA,IAAI,CAAC,KAAK,0CAAE,WAAW,CAAA,EAAE,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;QAEpC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,UAAC,IAAI;;YAC1B,IAAI,CAAA,MAAA,IAAI,CAAC,OAAO,0CAAE,EAAE,KAAI,KAAI,CAAC,mBAAmB,EAAE,CAAC;gBACjD,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,KAAI,CAAC,mBAAmB,EAAE,CAAC;gBAC3B,KAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAClC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACK,uCAAc,GAAtB;QAAA,iBAyCC;;QAxCC,uDAAuD;QACvD,IAAM,sBAAsB,GAAG,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,eAAe,0CAAE,OAAO,CAAC;QACrE,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,oCAAoC;QACpC,IAAM,WAAW,GAAG,MAAA,MAAA,IAAI,CAAC,KAAK,0CAAE,KAAK,0CAAE,OAAO,CAAC;QAC/C,IAAI,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,EAAE,EAAE,CAAC;YACpB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,mDAAmD;QACnD,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,mBAAmB,CAAC;QAClC,CAAC;QAED,kEAAkE;QAClE,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAE/B,6EAA6E;QAC7E,IAAI,CAAC,mBAAmB,GAAG,IAAI,OAAO,CAAO,UAAC,OAAO;;YACnD,KAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC;YAEnC,6FAA6F;YAC7F,IAAM,WAAW,GAAG,MAAA,MAAA,KAAI,CAAC,KAAK,0CAAE,KAAK,0CAAE,OAAO,CAAC;YAC/C,IAAI,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,EAAE,EAAE,CAAC;gBACpB,KAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,OAAO,EAAE,CAAC;gBACV,KAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAClC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAEK,6BAAI,GAAV,UAAW,KAAsB;;;;4BAC/B,qBAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAA;;wBAAhC,SAAgC,CAAC;;;;;KAClC;IAED;;;;;OAKG;IACG,uCAAc,GAApB,UAAqB,KAAsB;;;;;;;;wBACzC,IAAI,CAAC,QAAQ,CAAC,sDAA+C,KAAK,CAAC,MAAM,WAAQ,CAAC,CAAC;wBAEnF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BACvB,sBAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAC;wBAChC,CAAC;;;;wBAGO,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;wBAEpC,mCAAmC;wBACnC,IAAI,IAAI,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC;4BAC7B,IAAI,CAAC,QAAQ,CAAC,kDAA2C,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC;4BAC/E,sBAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAC;wBAChC,CAAC;wBAED,uEAAuE;wBACvE,wDAAwD;wBACxD,qBAAM,IAAI,CAAC,cAAc,EAAE,EAAA;;wBAF3B,uEAAuE;wBACvE,wDAAwD;wBACxD,SAA2B,CAAC;wBACtB,cAAY,MAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,0CAAE,EAAE,CAAC;wBAE9B,qBAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;gCAC5C,IAAM,aAAa,GAAG,IAAA,4BAAgB,EAAC,KAAK,CAAC,CAAC;gCAC9C,IAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;gCAE3C,2DAA2D;gCAC3D,IAAI,aAAa,CAAC,YAAY,IAAI,aAAa,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oCACxE,KAAgB,UAA0B,EAA1B,KAAA,aAAa,CAAC,YAAY,EAA1B,cAA0B,EAA1B,IAA0B,EAAE,CAAC;wCAAxC,IAAM,CAAC,SAAA;wCACV,KAAI,CAAC,QAAQ,CAAC,qDAA8C,CAAC,CAAC,IAAI,sBAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAE,CAAC,CAAC;oCAC5G,CAAC;gCACH,CAAC;gCAEK,IAAA,KAAkC,KAAI,CAAC,OAAO,EAA5C,GAAG,SAAA,EAAE,cAAc,oBAAA,EAAE,MAAM,YAAiB,CAAC;gCAErD,IAAM,KAAuC,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,EAAE,EAAzD,OAAO,aAAA,EAAK,oBAAoB,cAAlC,WAAoC,CAAuB,CAAC;gCAElE,2BAA2B;gCAC3B,KAAI,CAAC,QAAQ,CAAC,kCAA2B,KAAK,CAAC,MAAM,uBAAa,GAAG,CAAE,CAAC,CAAC;gCAEzE,wCAAwC;gCACxC,IAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gCACzC,IAAM,SAAS,GAAG,UAAU,CAAC;oCAC3B,UAAU,CAAC,KAAK,EAAE,CAAC;oCACnB,KAAI,CAAC,QAAQ,CAAC,6CAA6C,CAAC,CAAC;gCAC/D,CAAC,EAAE,KAAK,CAAC,CAAC;gCAEV,OAAO,KAAK,CAAC,GAAG,aACd,MAAM,EAAE,MAAM,EACd,OAAO,+BACL,cAAc,EAAE,kBAAkB,IAC/B,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC,GACf,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACvC,CAAC,WAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,WAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAE1D,IAAI,MAAA,EACJ,MAAM,EAAE,UAAU,CAAC,MAAM,IAGtB,CAAC,oBAAoB,aAApB,oBAAoB,cAApB,oBAAoB,GAAI,EAAE,CAAC,EAC/B;qCACC,IAAI,CAAC,UAAO,QAAQ;;;;;gDACnB,YAAY,CAAC,SAAS,CAAC,CAAC;gDACxB,6BAA6B;gDAC7B,IAAI,CAAC,QAAQ,CAAC,0CAAmC,QAAQ,CAAC,MAAM,CAAE,CAAC,CAAC;gDAEpE,mCAAmC;gDACnC,IAAI,CAAC,mBAAmB,GAAG,CAAC,CAAC;gDAE7B,IAAI,QAAQ,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;oDAC1C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;oDACtD,IAAI,CAAC,QAAQ,CAAC,uDAAgD,IAAI,CAAC,aAAa,CAAE,CAAC,CAAC;gDACtF,CAAC;qDAGG,CAAA,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAA,EAA/C,wBAA+C;gDACpC,qBAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,cAAM,OAAA,EAAE,EAAF,CAAE,CAAC,EAAA;;gDAA5C,IAAI,GAAG,SAAqC;gDAClD,IAAI,CAAC,QAAQ,CAAC,gDAAyC,QAAQ,CAAC,MAAM,cAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAE,CAAC,CAAC;;oDAGlG,sBAAO,QAAQ,EAAC;;;qCACjB,CAAC;qCACD,KAAK,CAAC,UAAC,KAAK;oCACX,YAAY,CAAC,SAAS,CAAC,CAAC;oCACxB,uBAAuB;oCACvB,KAAI,CAAC,QAAQ,CAAC,yCAAkC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,OAAO,KAAI,KAAK,CAAE,CAAC,CAAC;oCAE3E,4BAA4B;oCAC5B,KAAI,CAAC,mBAAmB,EAAE,CAAC;oCAE3B,mFAAmF;oCACnF,IAAI,KAAI,CAAC,mBAAmB,IAAI,wBAAwB,EAAE,CAAC;wCACzD,KAAI,CAAC,aAAa,GAAG,IAAI,IAAI,CAAC,KAAI,CAAC,MAAM,EAAE,GAAG,kBAAkB,CAAC,CAAC;wCAClE,kDAAkD;wCAClD,KAAI,CAAC,mBAAmB,GAAG,CAAC,CAAC;wCAC7B,KAAI,CAAC,QAAQ,CAAC,6DAA6D,CAAC,CAAC;oCAC/E,CAAC;oCAED,4EAA4E;oCAC5E,4EAA4E;oCAC5E,OAAO,SAAS,CAAC;gCACnB,CAAC,CAAC,CAAC;4BACP,CAAC,CAAC,EAAA;;wBAhFI,QAAQ,GAAG,SAgFf;wBAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;4BACd,sBAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAC;wBAC/B,CAAC;wBACD,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;4BACpD,sBAAO;oCACL,OAAO,EAAE,UAAU;oCACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;iCACxB,EAAC;wBACJ,CAAC;wBACD,sBAAO;gCACL,OAAO,EAAE,UAAU;gCACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;6BACxB,EAAC;;;wBAEF,yEAAyE;wBACzE,uEAAuE;wBACvE,sBAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAC;;;;;KAEhC;IAEQ,sCAAa,GAAtB;;QACE,OAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAc,CAAC,MAAM,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,UAAU,mCAAI,EAAE,CAAC,CAAC;IAC/E,CAAC;IAEQ,kCAAS,GAAlB;QACE,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,0CAAiB,GAAzB,UAA0B,QAAkB;QAC1C,IAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,IAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE7D,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAEvC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClB,OAAO,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;YACtC,CAAC;YAED,IAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAE1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACjD,CAAC;IACH,qBAAC;AAAD,CAAC,AAnQD,CAAoC,yBAAa,GAmQhD;AAnQY,wCAAc","sourcesContent":["import { BaseTransport, createPromiseBuffer, getTransportBody, VERSION } from '@grafana/faro-core';\nimport type { Patterns, PromiseBuffer, TransportItem } from '@grafana/faro-core';\n\nimport type { FetchTransportOptions, FetchTransportSendResult } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5;\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\nconst MAX_CONSECUTIVE_FAILURES = 3;\nconst FAILURE_BACKOFF_MS = 30000; // 30 seconds\n\nconst TOO_MANY_REQUESTS = 429;\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-react-native:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private disabledUntil: Date;\n private consecutiveFailures: number = 0;\n private sessionReadyPromise: Promise<void> | null = null;\n private sessionReadyResolve: (() => void) | null = null;\n private sessionReady: boolean = false;\n private metasListenerRegistered: boolean = false;\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n // Align with getNow so tests (and apps) that supply a clock do not see spurious backoff\n this.disabledUntil = new Date(this.getNow());\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n /**\n * Register a listener for metas changes to detect when session becomes available.\n * Uses faro-core's metas listener pattern instead of polling with setTimeout.\n */\n private registerSessionListener(): void {\n if (this.metasListenerRegistered || !this.metas?.addListener) {\n return;\n }\n\n this.metasListenerRegistered = true;\n\n this.metas.addListener((meta) => {\n if (meta.session?.id && this.sessionReadyResolve) {\n this.sessionReady = true;\n this.sessionReadyResolve();\n this.sessionReadyResolve = null;\n }\n });\n }\n\n /**\n * Wait for session to be available before sending.\n * This prevents 400 errors from the collector due to missing X-Faro-Session-Id header.\n *\n * Only waits if session tracking is enabled. If disabled, returns immediately.\n */\n private waitForSession(): Promise<void> {\n // Only wait for session if session tracking is enabled\n const sessionTrackingEnabled = this.config?.sessionTracking?.enabled;\n if (!sessionTrackingEnabled) {\n return Promise.resolve();\n }\n\n // Already have session\n if (this.sessionReady) {\n return Promise.resolve();\n }\n\n // Check if session is now available\n const sessionMeta = this.metas?.value?.session;\n if (sessionMeta?.id) {\n this.sessionReady = true;\n return Promise.resolve();\n }\n\n // Return existing promise if we're already waiting\n if (this.sessionReadyPromise) {\n return this.sessionReadyPromise;\n }\n\n // Register listener to be notified when session becomes available\n this.registerSessionListener();\n\n // Create a promise that resolves when session becomes available via listener\n this.sessionReadyPromise = new Promise<void>((resolve) => {\n this.sessionReadyResolve = resolve;\n\n // Also check immediately in case session was set between our check and listener registration\n const sessionMeta = this.metas?.value?.session;\n if (sessionMeta?.id) {\n this.sessionReady = true;\n resolve();\n this.sessionReadyResolve = null;\n }\n });\n\n return this.sessionReadyPromise;\n }\n\n async send(items: TransportItem[]): Promise<void> {\n await this.sendWithResult(items);\n }\n\n /**\n * Sends a batch and reports whether the collector accepted it.\n * The request header uses the live session for collector accounting. Payload\n * metadata remains independent so delayed signals can retain their original\n * session.\n */\n async sendWithResult(items: TransportItem[]): Promise<FetchTransportSendResult> {\n this.logDebug(`FetchTransport.sendWithResult() called with ${items.length} items`);\n\n if (items.length === 0) {\n return { outcome: 'skipped' };\n }\n\n try {\n const now = new Date(this.getNow());\n\n // Check if we're in backoff period\n if (this.disabledUntil > now) {\n this.logDebug(`FetchTransport: in backoff period until ${this.disabledUntil}`);\n return { outcome: 'skipped' };\n }\n\n // The collector uses the header for session validation and accounting,\n // independently of the session carried by each payload.\n await this.waitForSession();\n const sessionId = this.metas.value.session?.id;\n\n const response = await this.promiseBuffer.add(() => {\n const transportBody = getTransportBody(items);\n const body = JSON.stringify(transportBody);\n\n // DEBUG: Log measurement payloads to see what's being sent\n if (transportBody.measurements && transportBody.measurements.length > 0) {\n for (const m of transportBody.measurements) {\n this.logDebug(`FetchTransport: measurement payload - type=${m.type}, values=${JSON.stringify(m.values)}`);\n }\n }\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers, ...restOfRequestOptions } = requestOptions ?? {};\n\n // DEBUG: Log fetch attempt\n this.logDebug(`FetchTransport: sending ${items.length} items to ${url}`);\n\n // Create an AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n this.logDebug(`FetchTransport: request timed out after 10s`);\n }, 10000);\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(headers ?? {}),\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n signal: controller.signal,\n // Note: React Native doesn't support keepalive\n // keepalive: body.length <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then(async (response) => {\n clearTimeout(timeoutId);\n // DEBUG: Log response status\n this.logDebug(`FetchTransport: response status ${response.status}`);\n\n // Reset failure counter on success\n this.consecutiveFailures = 0;\n\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logDebug(`FetchTransport: rate limited, disabled until ${this.disabledUntil}`);\n }\n\n // Log non-success responses for debugging\n if (response.status < 200 || response.status >= 300) {\n const text = await response.text().catch(() => '');\n this.logDebug(`FetchTransport: non-success response: ${response.status} ${text.slice(0, 200)}`);\n }\n\n return response;\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n // DEBUG: Log the error\n this.logDebug(`FetchTransport: fetch failed - ${error?.message || error}`);\n\n // Increment failure counter\n this.consecutiveFailures++;\n\n // After MAX_CONSECUTIVE_FAILURES, enable circuit breaker to prevent infinite loops\n if (this.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {\n this.disabledUntil = new Date(this.getNow() + FAILURE_BACKOFF_MS);\n // Reset counter so we can try again after backoff\n this.consecutiveFailures = 0;\n this.logDebug(`FetchTransport: circuit breaker activated, disabled for 30s`);\n }\n\n // Do NOT log errors to console - this causes infinite loops in React Native\n // when the DevTools console override intercepts even unpatchedConsole calls\n return undefined;\n });\n });\n\n if (!response) {\n return { outcome: 'failed' };\n }\n if (response.status >= 200 && response.status < 300) {\n return {\n outcome: 'accepted',\n status: response.status,\n };\n }\n return {\n outcome: 'rejected',\n status: response.status,\n };\n } catch {\n // Buffer full error - Do NOT log to console as it creates infinite loops\n // The error is typically \"Task buffer full\" when the device is offline\n return { outcome: 'failed' };\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/transports/fetch/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface FetchTransportRequestOptions extends Omit<RequestInit, 'body' | 'headers'> {\n headers?: Record<string, string>;\n}\n\nexport interface FetchTransportOptions {\n // url of the collector endpoint\n url: string;\n\n // will be added as `x-api-key` header\n apiKey?: string;\n // how many requests to buffer in total\n bufferSize?: number;\n // how many requests to execute concurrently\n concurrency?: number;\n // if rate limit response does not include a Retry-After header,\n // how many milliseconds to back off before attempting a request.\n // intermediate events will be dropped, not buffered\n defaultRateLimitBackoffMs?: number;\n // get current date. for mocking purposes in tests\n getNow?: ClockFn;\n // addition options for global.Fetch\n requestOptions?: FetchTransportRequestOptions;\n}\n\nexport type ClockFn = () => number;\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/transports/fetch/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface FetchTransportRequestOptions extends Omit<RequestInit, 'body' | 'headers'> {\n headers?: Record<string, string>;\n}\n\nexport interface FetchTransportOptions {\n // url of the collector endpoint\n url: string;\n\n // will be added as `x-api-key` header\n apiKey?: string;\n // how many requests to buffer in total\n bufferSize?: number;\n // how many requests to execute concurrently\n concurrency?: number;\n // if rate limit response does not include a Retry-After header,\n // how many milliseconds to back off before attempting a request.\n // intermediate events will be dropped, not buffered\n defaultRateLimitBackoffMs?: number;\n // get current date. for mocking purposes in tests\n getNow?: ClockFn;\n // addition options for global.Fetch\n requestOptions?: FetchTransportRequestOptions;\n}\n\nexport type ClockFn = () => number;\n\nexport type FetchTransportSendOutcome = 'accepted' | 'rejected' | 'failed' | 'skipped';\n\nexport interface FetchTransportSendResult {\n outcome: FetchTransportSendOutcome;\n status?: number;\n}\n"]}
|
|
@@ -55,7 +55,7 @@ var DEFAULT_CHECK_INTERVAL_MS = 30000;
|
|
|
55
55
|
* Uses @react-native-community/netinfo when available, otherwise falls back
|
|
56
56
|
* to basic fetch-based connectivity detection.
|
|
57
57
|
*
|
|
58
|
-
*
|
|
58
|
+
* Monitors network connectivity for offline transport flush behavior.
|
|
59
59
|
*/
|
|
60
60
|
var DefaultConnectivityService = /** @class */ (function () {
|
|
61
61
|
function DefaultConnectivityService(checkIntervalMs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectivityService.js","sourceRoot":"","sources":["../../../../src/transports/offline/ConnectivityService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConnectivityService } from './types';\n\n// Try to use NetInfo if available, otherwise fall back to basic online detection\nlet NetInfo: {\n fetch: () => Promise<{ isConnected: boolean | null }>;\n addEventListener: (callback: (state: { isConnected: boolean | null }) => void) => () => void;\n} | null = null;\n\ntry {\n NetInfo = require('@react-native-community/netinfo').default;\n} catch {\n // NetInfo not available, will fall back to basic detection\n}\n\n/**\n * Default connectivity check interval in milliseconds.\n */\nconst DEFAULT_CHECK_INTERVAL_MS = 30000;\n\n/**\n * Service for detecting network connectivity changes.\n *\n * Uses @react-native-community/netinfo when available, otherwise falls back\n * to basic fetch-based connectivity detection.\n *\n *
|
|
1
|
+
{"version":3,"file":"ConnectivityService.js","sourceRoot":"","sources":["../../../../src/transports/offline/ConnectivityService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConnectivityService } from './types';\n\n// Try to use NetInfo if available, otherwise fall back to basic online detection\nlet NetInfo: {\n fetch: () => Promise<{ isConnected: boolean | null }>;\n addEventListener: (callback: (state: { isConnected: boolean | null }) => void) => () => void;\n} | null = null;\n\ntry {\n NetInfo = require('@react-native-community/netinfo').default;\n} catch {\n // NetInfo not available, will fall back to basic detection\n}\n\n/**\n * Default connectivity check interval in milliseconds.\n */\nconst DEFAULT_CHECK_INTERVAL_MS = 30000;\n\n/**\n * Service for detecting network connectivity changes.\n *\n * Uses @react-native-community/netinfo when available, otherwise falls back\n * to basic fetch-based connectivity detection.\n *\n * Monitors network connectivity for offline transport flush behavior.\n */\nexport class DefaultConnectivityService implements ConnectivityService {\n private _isOnline: boolean = true;\n private readonly subscribers: Set<(isOnline: boolean) => void> = new Set();\n private unsubscribeNetInfo: (() => void) | null = null;\n private checkIntervalId: ReturnType<typeof setInterval> | null = null;\n private readonly checkIntervalMs: number;\n\n constructor(checkIntervalMs: number = DEFAULT_CHECK_INTERVAL_MS) {\n this.checkIntervalMs = checkIntervalMs;\n this.initialize();\n }\n\n get isOnline(): boolean {\n return this._isOnline;\n }\n\n subscribe(callback: (isOnline: boolean) => void): () => void {\n this.subscribers.add(callback);\n // Immediately notify subscriber of current state\n callback(this._isOnline);\n\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n dispose(): void {\n if (this.unsubscribeNetInfo) {\n this.unsubscribeNetInfo();\n this.unsubscribeNetInfo = null;\n }\n if (this.checkIntervalId) {\n clearInterval(this.checkIntervalId);\n this.checkIntervalId = null;\n }\n this.subscribers.clear();\n }\n\n private initialize(): void {\n if (NetInfo) {\n this.initializeWithNetInfo();\n } else {\n this.initializeWithPolling();\n }\n }\n\n private initializeWithNetInfo(): void {\n if (!NetInfo) return;\n\n // Initial check\n NetInfo.fetch().then((state) => {\n this.setOnline(state.isConnected ?? true);\n });\n\n // Subscribe to changes\n this.unsubscribeNetInfo = NetInfo.addEventListener((state) => {\n this.setOnline(state.isConnected ?? true);\n });\n }\n\n private initializeWithPolling(): void {\n // Initial check\n this.checkConnectivity();\n\n // Poll periodically\n this.checkIntervalId = setInterval(() => {\n this.checkConnectivity();\n }, this.checkIntervalMs);\n }\n\n private async checkConnectivity(): Promise<void> {\n try {\n // Simple fetch-based connectivity check\n // We use a small, fast endpoint\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n await fetch('https://one.one.one.one/cdn-cgi/trace', {\n method: 'HEAD',\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n this.setOnline(true);\n } catch {\n this.setOnline(false);\n }\n }\n\n private setOnline(isOnline: boolean): void {\n if (this._isOnline !== isOnline) {\n this._isOnline = isOnline;\n this.notifySubscribers();\n }\n }\n\n private notifySubscribers(): void {\n this.subscribers.forEach((subscriber) => {\n try {\n subscriber(this._isOnline);\n } catch {\n // Ignore subscriber errors\n }\n });\n }\n}\n"]}
|
|
@@ -53,7 +53,7 @@ var DEFAULT_MAX_CACHE_SIZE = 1000;
|
|
|
53
53
|
* File-based offline cache implementation using AsyncStorage.
|
|
54
54
|
*
|
|
55
55
|
* Stores cached telemetry payloads as JSONL (one JSON object per line)
|
|
56
|
-
*
|
|
56
|
+
* Persistent offline telemetry cache backed by AsyncStorage.
|
|
57
57
|
*
|
|
58
58
|
* Uses a mutex pattern for thread-safe file access.
|
|
59
59
|
*/
|
|
@@ -178,7 +178,7 @@ var AsyncStorageOfflineCache = /** @class */ (function () {
|
|
|
178
178
|
};
|
|
179
179
|
/**
|
|
180
180
|
* Execute an operation with a mutex lock to ensure thread-safe access.
|
|
181
|
-
*
|
|
181
|
+
* Async lock to serialize cache read/write operations.
|
|
182
182
|
*/
|
|
183
183
|
AsyncStorageOfflineCache.prototype.withLock = function (operation) {
|
|
184
184
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OfflineCache.js","sourceRoot":"","sources":["../../../../src/transports/offline/OfflineCache.ts"],"names":[],"mappings":"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","sourcesContent":["import AsyncStorage from '@react-native-async-storage/async-storage';\n\nimport type { CachedPayload, OfflineCache } from './types';\n\n/**\n * Default storage key prefix for the offline cache.\n */\nconst DEFAULT_STORAGE_KEY_PREFIX = 'faro_offline_cache';\n\n/**\n * Default maximum number of cached payloads.\n */\nconst DEFAULT_MAX_CACHE_SIZE = 1000;\n\n/**\n * File-based offline cache implementation using AsyncStorage.\n *\n * Stores cached telemetry payloads as JSONL (one JSON object per line)\n *
|
|
1
|
+
{"version":3,"file":"OfflineCache.js","sourceRoot":"","sources":["../../../../src/transports/offline/OfflineCache.ts"],"names":[],"mappings":"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","sourcesContent":["import AsyncStorage from '@react-native-async-storage/async-storage';\n\nimport type { CachedPayload, OfflineCache } from './types';\n\n/**\n * Default storage key prefix for the offline cache.\n */\nconst DEFAULT_STORAGE_KEY_PREFIX = 'faro_offline_cache';\n\n/**\n * Default maximum number of cached payloads.\n */\nconst DEFAULT_MAX_CACHE_SIZE = 1000;\n\n/**\n * File-based offline cache implementation using AsyncStorage.\n *\n * Stores cached telemetry payloads as JSONL (one JSON object per line)\n * Persistent offline telemetry cache backed by AsyncStorage.\n *\n * Uses a mutex pattern for thread-safe file access.\n */\nexport class AsyncStorageOfflineCache implements OfflineCache {\n private readonly storageKey: string;\n private readonly maxCacheSize: number;\n private lockPromise: Promise<void> = Promise.resolve();\n\n constructor(options: { storageKeyPrefix?: string; maxCacheSize?: number } = {}) {\n this.storageKey = `${options.storageKeyPrefix ?? DEFAULT_STORAGE_KEY_PREFIX}_data`;\n this.maxCacheSize = options.maxCacheSize ?? DEFAULT_MAX_CACHE_SIZE;\n }\n\n async write(payload: CachedPayload): Promise<void> {\n await this.withLock(async () => {\n const payloads = await this.readAllInternal();\n\n // Add new payload\n payloads.push(payload);\n\n // Trim to max size (remove oldest entries)\n while (payloads.length > this.maxCacheSize) {\n payloads.shift();\n }\n\n await this.writeAll(payloads);\n });\n }\n\n async readAll(): Promise<CachedPayload[]> {\n return this.withLock(async () => {\n return this.readAllInternal();\n });\n }\n\n async clear(): Promise<void> {\n await this.withLock(async () => {\n await AsyncStorage.removeItem(this.storageKey);\n });\n }\n\n async removeByTimestamps(timestamps: number[]): Promise<void> {\n if (timestamps.length === 0) return;\n\n const timestampSet = new Set(timestamps);\n\n await this.withLock(async () => {\n const payloads = await this.readAllInternal();\n const remaining = payloads.filter((p) => !timestampSet.has(p.timestamp));\n await this.writeAll(remaining);\n });\n }\n\n async getCount(): Promise<number> {\n const payloads = await this.readAllInternal();\n return payloads.length;\n }\n\n /**\n * Execute an operation with a mutex lock to ensure thread-safe access.\n * Async lock to serialize cache read/write operations.\n */\n private async withLock<T>(operation: () => Promise<T>): Promise<T> {\n const currentLock = this.lockPromise;\n let resolveLock: () => void;\n this.lockPromise = new Promise<void>((resolve) => {\n resolveLock = resolve;\n });\n\n try {\n await currentLock;\n return await operation();\n } finally {\n resolveLock!();\n }\n }\n\n private async readAllInternal(): Promise<CachedPayload[]> {\n try {\n const data = await AsyncStorage.getItem(this.storageKey);\n if (!data) {\n return [];\n }\n\n const parsed = JSON.parse(data);\n if (!Array.isArray(parsed)) {\n return [];\n }\n\n return parsed.filter(this.isValidCachedPayload);\n } catch {\n // If parsing fails, return empty array\n return [];\n }\n }\n\n private async writeAll(payloads: CachedPayload[]): Promise<void> {\n if (payloads.length === 0) {\n await AsyncStorage.removeItem(this.storageKey);\n } else {\n await AsyncStorage.setItem(this.storageKey, JSON.stringify(payloads));\n }\n }\n\n private isValidCachedPayload(payload: unknown): payload is CachedPayload {\n if (typeof payload !== 'object' || payload === null) {\n return false;\n }\n\n const p = payload as Record<string, unknown>;\n return typeof p['timestamp'] === 'number' && Array.isArray(p['items']);\n }\n}\n"]}
|
|
@@ -66,8 +66,7 @@ var DEFAULT_MAX_CACHE_DURATION_MS = 3 * 24 * 60 * 60 * 1000;
|
|
|
66
66
|
* When the device is offline, telemetry is cached to AsyncStorage.
|
|
67
67
|
* When connectivity is restored, cached telemetry is replayed through the wrapped transports.
|
|
68
68
|
*
|
|
69
|
-
*
|
|
70
|
-
* - Uses AsyncStorage for persistent caching (matching Flutter's SharedPreferences)
|
|
69
|
+
* Uses AsyncStorage for persistent offline telemetry caching.
|
|
71
70
|
* - Respects maxCacheDuration to skip expired entries
|
|
72
71
|
* - Uses mutex pattern for thread-safe cache access
|
|
73
72
|
* - Excludes itself when replaying to prevent infinite loops
|
|
@@ -225,7 +224,7 @@ var OfflineTransport = /** @class */ (function (_super) {
|
|
|
225
224
|
};
|
|
226
225
|
/**
|
|
227
226
|
* Replay cached payloads through other transports.
|
|
228
|
-
*
|
|
227
|
+
* Reads cached telemetry from AsyncStorage.
|
|
229
228
|
*/
|
|
230
229
|
OfflineTransport.prototype.replayCachedPayloads = function () {
|
|
231
230
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -292,7 +291,7 @@ var OfflineTransport = /** @class */ (function (_super) {
|
|
|
292
291
|
};
|
|
293
292
|
/**
|
|
294
293
|
* Send items to all other registered transports.
|
|
295
|
-
*
|
|
294
|
+
* Sends cached telemetry when connectivity is restored.
|
|
296
295
|
*/
|
|
297
296
|
OfflineTransport.prototype.sendToOtherTransports = function (items) {
|
|
298
297
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/offline/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseTransport, VERSION } from '@grafana/faro-core';\nimport type { Patterns, Transport, TransportItem } from '@grafana/faro-core';\n\nimport { DefaultConnectivityService } from './ConnectivityService';\nimport { AsyncStorageOfflineCache } from './OfflineCache';\nimport type { CachedPayload, ConnectivityService, OfflineCache, OfflineTransportOptions } from './types';\n\n/**\n * Default maximum cache duration: 3 days in milliseconds.\n */\nconst DEFAULT_MAX_CACHE_DURATION_MS = 3 * 24 * 60 * 60 * 1000;\n\n/**\n * OfflineTransport - Caches telemetry when offline and replays when online.\n *\n * This transport wraps other transports and provides offline caching functionality.\n * When the device is offline, telemetry is cached to AsyncStorage.\n * When connectivity is restored, cached telemetry is replayed through the wrapped transports.\n *\n * Implementation follows Flutter SDK's OfflineTransport pattern:\n * - Uses AsyncStorage for persistent caching (matching Flutter's SharedPreferences)\n * - Respects maxCacheDuration to skip expired entries\n * - Uses mutex pattern for thread-safe cache access\n * - Excludes itself when replaying to prevent infinite loops\n *\n * @example\n * ```typescript\n * import { initializeFaro, FetchTransport, OfflineTransport } from '@grafana/faro-react-native';\n *\n * initializeFaro({\n * url: 'https://collector.example.com',\n * transports: [\n * new OfflineTransport({\n * maxCacheDurationMs: 3 * 24 * 60 * 60 * 1000, // 3 days\n * }),\n * new FetchTransport({ url: 'https://collector.example.com' }),\n * ],\n * });\n * ```\n */\nexport class OfflineTransport extends BaseTransport {\n readonly name = '@grafana/faro-react-native:transport-offline';\n readonly version = VERSION;\n\n private readonly cache: OfflineCache;\n private readonly connectivityService: ConnectivityService;\n private readonly maxCacheDurationMs: number;\n private readonly otherTransports: Transport[] = [];\n private unsubscribeConnectivity: (() => void) | null = null;\n private isReplaying: boolean = false;\n\n constructor(options: OfflineTransportOptions = {}) {\n super();\n\n this.maxCacheDurationMs = options.maxCacheDurationMs ?? DEFAULT_MAX_CACHE_DURATION_MS;\n\n this.cache = new AsyncStorageOfflineCache({\n storageKeyPrefix: options.storageKeyPrefix,\n maxCacheSize: options.maxCacheSize,\n });\n\n this.connectivityService = new DefaultConnectivityService(options.connectivityCheckIntervalMs);\n\n // Subscribe to connectivity changes\n this.unsubscribeConnectivity = this.connectivityService.subscribe((isOnline) => {\n if (isOnline && !this.isReplaying) {\n this.replayCachedPayloads();\n }\n });\n }\n\n /**\n * Send telemetry items.\n *\n * When offline, items are cached for later replay.\n * When online, this transport does nothing (other transports handle sending).\n */\n async send(items: TransportItem | TransportItem[]): Promise<void> {\n const itemsArray = Array.isArray(items) ? items : [items];\n\n if (itemsArray.length === 0) {\n return;\n }\n\n if (!this.connectivityService.isOnline) {\n // Cache items when offline\n const payload: CachedPayload = {\n timestamp: Date.now(),\n items: itemsArray,\n };\n\n try {\n await this.cache.write(payload);\n this.logDebug(`Cached ${itemsArray.length} items for offline replay`);\n } catch (error) {\n this.logError('Failed to cache offline payload', error);\n }\n }\n // When online, do nothing - other transports handle sending\n }\n\n override getIgnoreUrls(): Patterns {\n return [];\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n /**\n * Register other transports for replay.\n * Called by the transport system after initialization.\n */\n setOtherTransports(transports: Transport[]): void {\n this.otherTransports.length = 0;\n for (const transport of transports) {\n if (transport !== this) {\n this.otherTransports.push(transport);\n }\n }\n }\n\n /**\n * Get the current number of cached payloads.\n */\n async getCachedCount(): Promise<number> {\n return this.cache.getCount();\n }\n\n /**\n * Manually trigger replay of cached payloads.\n * Useful for testing or when you want to force a replay attempt.\n */\n async forceReplay(): Promise<void> {\n if (this.connectivityService.isOnline) {\n await this.replayCachedPayloads();\n }\n }\n\n /**\n * Clear all cached payloads.\n */\n async clearCache(): Promise<void> {\n await this.cache.clear();\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (this.unsubscribeConnectivity) {\n this.unsubscribeConnectivity();\n this.unsubscribeConnectivity = null;\n }\n this.connectivityService.dispose();\n }\n\n /**\n * Replay cached payloads through other transports.\n * Follows Flutter SDK's _readFromFile pattern.\n */\n private async replayCachedPayloads(): Promise<void> {\n if (this.isReplaying) {\n return;\n }\n\n this.isReplaying = true;\n\n try {\n const payloads = await this.cache.readAll();\n\n if (payloads.length === 0) {\n return;\n }\n\n this.logDebug(`Replaying ${payloads.length} cached payloads`);\n\n const now = Date.now();\n const successfulTimestamps: number[] = [];\n\n for (const payload of payloads) {\n // Skip expired payloads\n if (now - payload.timestamp > this.maxCacheDurationMs) {\n this.logDebug(`Skipping expired payload from ${new Date(payload.timestamp).toISOString()}`);\n successfulTimestamps.push(payload.timestamp);\n continue;\n }\n\n const success = await this.sendToOtherTransports(payload.items);\n\n if (success) {\n successfulTimestamps.push(payload.timestamp);\n }\n }\n\n // Remove successfully sent or expired payloads\n if (successfulTimestamps.length > 0) {\n await this.cache.removeByTimestamps(successfulTimestamps);\n this.logDebug(`Removed ${successfulTimestamps.length} payloads from cache`);\n }\n } catch (error) {\n this.logError('Failed to replay cached payloads', error);\n } finally {\n this.isReplaying = false;\n }\n }\n\n /**\n * Send items to all other registered transports.\n * Follows Flutter SDK's _sendCachedData pattern.\n */\n private async sendToOtherTransports(items: TransportItem[]): Promise<boolean> {\n if (this.otherTransports.length === 0) {\n this.logWarn('No other transports registered for offline replay');\n return false;\n }\n\n try {\n for (const transport of this.otherTransports) {\n await transport.send(items);\n }\n return true;\n } catch (error) {\n this.logError('Failed to send cached payload to transports', error);\n return false;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/offline/transport.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAA4D;AAG5D,6DAAmE;AACnE,+CAA0D;AAG1D;;GAEG;AACH,IAAM,6BAA6B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH;IAAsC,oCAAa;IAWjD,0BAAY,OAAqC;QAArC,wBAAA,EAAA,YAAqC;;QAC/C,YAAA,MAAK,WAAE,SAAC;QAXD,UAAI,GAAG,8CAA8C,CAAC;QACtD,aAAO,GAAG,mBAAO,CAAC;QAKV,qBAAe,GAAgB,EAAE,CAAC;QAC3C,6BAAuB,GAAwB,IAAI,CAAC;QACpD,iBAAW,GAAY,KAAK,CAAC;QAKnC,KAAI,CAAC,kBAAkB,GAAG,MAAA,OAAO,CAAC,kBAAkB,mCAAI,6BAA6B,CAAC;QAEtF,KAAI,CAAC,KAAK,GAAG,IAAI,uCAAwB,CAAC;YACxC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC,CAAC;QAEH,KAAI,CAAC,mBAAmB,GAAG,IAAI,gDAA0B,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;QAE/F,oCAAoC;QACpC,KAAI,CAAC,uBAAuB,GAAG,KAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,UAAC,QAAQ;YACzE,IAAI,QAAQ,IAAI,CAAC,KAAI,CAAC,WAAW,EAAE,CAAC;gBAClC,KAAI,CAAC,oBAAoB,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC;;IACL,CAAC;IAED;;;;;OAKG;IACG,+BAAI,GAAV,UAAW,KAAsC;;;;;;wBACzC,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;wBAE1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC5B,sBAAO;wBACT,CAAC;6BAEG,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAlC,wBAAkC;wBAE9B,OAAO,GAAkB;4BAC7B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;4BACrB,KAAK,EAAE,UAAU;yBAClB,CAAC;;;;wBAGA,qBAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAA;;wBAA/B,SAA+B,CAAC;wBAChC,IAAI,CAAC,QAAQ,CAAC,iBAAU,UAAU,CAAC,MAAM,8BAA2B,CAAC,CAAC;;;;wBAEtE,IAAI,CAAC,QAAQ,CAAC,iCAAiC,EAAE,OAAK,CAAC,CAAC;;;;;;KAI7D;IAEQ,wCAAa,GAAtB;QACE,OAAO,EAAE,CAAC;IACZ,CAAC;IAEQ,oCAAS,GAAlB;QACE,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,6CAAkB,GAAlB,UAAmB,UAAuB;QACxC,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC;QAChC,KAAwB,UAAU,EAAV,yBAAU,EAAV,wBAAU,EAAV,IAAU,EAAE,CAAC;YAAhC,IAAM,SAAS,mBAAA;YAClB,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACG,yCAAc,GAApB;;;gBACE,sBAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAC;;;KAC9B;IAED;;;OAGG;IACG,sCAAW,GAAjB;;;;;6BACM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAjC,wBAAiC;wBACnC,qBAAM,IAAI,CAAC,oBAAoB,EAAE,EAAA;;wBAAjC,SAAiC,CAAC;;;;;;KAErC;IAED;;OAEG;IACG,qCAAU,GAAhB;;;;4BACE,qBAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAA;;wBAAxB,SAAwB,CAAC;;;;;KAC1B;IAED;;OAEG;IACH,kCAAO,GAAP;QACE,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACjC,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC/B,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAED;;;OAGG;IACW,+CAAoB,GAAlC;;;;;;wBACE,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;4BACrB,sBAAO;wBACT,CAAC;wBAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAGL,qBAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAA;;wBAArC,QAAQ,GAAG,SAA0B;wBAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC1B,sBAAO;wBACT,CAAC;wBAED,IAAI,CAAC,QAAQ,CAAC,oBAAa,QAAQ,CAAC,MAAM,qBAAkB,CAAC,CAAC;wBAExD,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;wBACjB,oBAAoB,GAAa,EAAE,CAAC;8BAEZ,EAAR,qBAAQ;;;6BAAR,CAAA,sBAAQ,CAAA;wBAAnB,OAAO;wBAChB,wBAAwB;wBACxB,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;4BACtD,IAAI,CAAC,QAAQ,CAAC,wCAAiC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAE,CAAC,CAAC;4BAC5F,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;4BAC7C,wBAAS;wBACX,CAAC;wBAEe,qBAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAA;;wBAAzD,OAAO,GAAG,SAA+C;wBAE/D,IAAI,OAAO,EAAE,CAAC;4BACZ,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;wBAC/C,CAAC;;;wBAZmB,IAAQ,CAAA;;;6BAgB1B,CAAA,oBAAoB,CAAC,MAAM,GAAG,CAAC,CAAA,EAA/B,wBAA+B;wBACjC,qBAAM,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,EAAA;;wBAAzD,SAAyD,CAAC;wBAC1D,IAAI,CAAC,QAAQ,CAAC,kBAAW,oBAAoB,CAAC,MAAM,yBAAsB,CAAC,CAAC;;;;;wBAG9E,IAAI,CAAC,QAAQ,CAAC,kCAAkC,EAAE,OAAK,CAAC,CAAC;;;wBAEzD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;;;;;;KAE5B;IAED;;;OAGG;IACW,gDAAqB,GAAnC,UAAoC,KAAsB;;;;;;wBACxD,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BACtC,IAAI,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;4BAClE,sBAAO,KAAK,EAAC;wBACf,CAAC;;;;8BAG6C,EAApB,KAAA,IAAI,CAAC,eAAe;;;6BAApB,CAAA,cAAoB,CAAA;wBAAjC,SAAS;wBAClB,qBAAM,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAA;;wBAA3B,SAA2B,CAAC;;;wBADN,IAAoB,CAAA;;4BAG5C,sBAAO,IAAI,EAAC;;;wBAEZ,IAAI,CAAC,QAAQ,CAAC,6CAA6C,EAAE,OAAK,CAAC,CAAC;wBACpE,sBAAO,KAAK,EAAC;;;;;KAEhB;IACH,uBAAC;AAAD,CAAC,AA3LD,CAAsC,yBAAa,GA2LlD;AA3LY,4CAAgB","sourcesContent":["import { BaseTransport, VERSION } from '@grafana/faro-core';\nimport type { Patterns, Transport, TransportItem } from '@grafana/faro-core';\n\nimport { DefaultConnectivityService } from './ConnectivityService';\nimport { AsyncStorageOfflineCache } from './OfflineCache';\nimport type { CachedPayload, ConnectivityService, OfflineCache, OfflineTransportOptions } from './types';\n\n/**\n * Default maximum cache duration: 3 days in milliseconds.\n */\nconst DEFAULT_MAX_CACHE_DURATION_MS = 3 * 24 * 60 * 60 * 1000;\n\n/**\n * OfflineTransport - Caches telemetry when offline and replays when online.\n *\n * This transport wraps other transports and provides offline caching functionality.\n * When the device is offline, telemetry is cached to AsyncStorage.\n * When connectivity is restored, cached telemetry is replayed through the wrapped transports.\n *\n * Uses AsyncStorage for persistent offline telemetry caching.\n * - Respects maxCacheDuration to skip expired entries\n * - Uses mutex pattern for thread-safe cache access\n * - Excludes itself when replaying to prevent infinite loops\n *\n * @example\n * ```typescript\n * import { initializeFaro, FetchTransport, OfflineTransport } from '@grafana/faro-react-native';\n *\n * initializeFaro({\n * url: 'https://collector.example.com',\n * transports: [\n * new OfflineTransport({\n * maxCacheDurationMs: 3 * 24 * 60 * 60 * 1000, // 3 days\n * }),\n * new FetchTransport({ url: 'https://collector.example.com' }),\n * ],\n * });\n * ```\n */\nexport class OfflineTransport extends BaseTransport {\n readonly name = '@grafana/faro-react-native:transport-offline';\n readonly version = VERSION;\n\n private readonly cache: OfflineCache;\n private readonly connectivityService: ConnectivityService;\n private readonly maxCacheDurationMs: number;\n private readonly otherTransports: Transport[] = [];\n private unsubscribeConnectivity: (() => void) | null = null;\n private isReplaying: boolean = false;\n\n constructor(options: OfflineTransportOptions = {}) {\n super();\n\n this.maxCacheDurationMs = options.maxCacheDurationMs ?? DEFAULT_MAX_CACHE_DURATION_MS;\n\n this.cache = new AsyncStorageOfflineCache({\n storageKeyPrefix: options.storageKeyPrefix,\n maxCacheSize: options.maxCacheSize,\n });\n\n this.connectivityService = new DefaultConnectivityService(options.connectivityCheckIntervalMs);\n\n // Subscribe to connectivity changes\n this.unsubscribeConnectivity = this.connectivityService.subscribe((isOnline) => {\n if (isOnline && !this.isReplaying) {\n this.replayCachedPayloads();\n }\n });\n }\n\n /**\n * Send telemetry items.\n *\n * When offline, items are cached for later replay.\n * When online, this transport does nothing (other transports handle sending).\n */\n async send(items: TransportItem | TransportItem[]): Promise<void> {\n const itemsArray = Array.isArray(items) ? items : [items];\n\n if (itemsArray.length === 0) {\n return;\n }\n\n if (!this.connectivityService.isOnline) {\n // Cache items when offline\n const payload: CachedPayload = {\n timestamp: Date.now(),\n items: itemsArray,\n };\n\n try {\n await this.cache.write(payload);\n this.logDebug(`Cached ${itemsArray.length} items for offline replay`);\n } catch (error) {\n this.logError('Failed to cache offline payload', error);\n }\n }\n // When online, do nothing - other transports handle sending\n }\n\n override getIgnoreUrls(): Patterns {\n return [];\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n /**\n * Register other transports for replay.\n * Called by the transport system after initialization.\n */\n setOtherTransports(transports: Transport[]): void {\n this.otherTransports.length = 0;\n for (const transport of transports) {\n if (transport !== this) {\n this.otherTransports.push(transport);\n }\n }\n }\n\n /**\n * Get the current number of cached payloads.\n */\n async getCachedCount(): Promise<number> {\n return this.cache.getCount();\n }\n\n /**\n * Manually trigger replay of cached payloads.\n * Useful for testing or when you want to force a replay attempt.\n */\n async forceReplay(): Promise<void> {\n if (this.connectivityService.isOnline) {\n await this.replayCachedPayloads();\n }\n }\n\n /**\n * Clear all cached payloads.\n */\n async clearCache(): Promise<void> {\n await this.cache.clear();\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (this.unsubscribeConnectivity) {\n this.unsubscribeConnectivity();\n this.unsubscribeConnectivity = null;\n }\n this.connectivityService.dispose();\n }\n\n /**\n * Replay cached payloads through other transports.\n * Reads cached telemetry from AsyncStorage.\n */\n private async replayCachedPayloads(): Promise<void> {\n if (this.isReplaying) {\n return;\n }\n\n this.isReplaying = true;\n\n try {\n const payloads = await this.cache.readAll();\n\n if (payloads.length === 0) {\n return;\n }\n\n this.logDebug(`Replaying ${payloads.length} cached payloads`);\n\n const now = Date.now();\n const successfulTimestamps: number[] = [];\n\n for (const payload of payloads) {\n // Skip expired payloads\n if (now - payload.timestamp > this.maxCacheDurationMs) {\n this.logDebug(`Skipping expired payload from ${new Date(payload.timestamp).toISOString()}`);\n successfulTimestamps.push(payload.timestamp);\n continue;\n }\n\n const success = await this.sendToOtherTransports(payload.items);\n\n if (success) {\n successfulTimestamps.push(payload.timestamp);\n }\n }\n\n // Remove successfully sent or expired payloads\n if (successfulTimestamps.length > 0) {\n await this.cache.removeByTimestamps(successfulTimestamps);\n this.logDebug(`Removed ${successfulTimestamps.length} payloads from cache`);\n }\n } catch (error) {\n this.logError('Failed to replay cached payloads', error);\n } finally {\n this.isReplaying = false;\n }\n }\n\n /**\n * Send items to all other registered transports.\n * Sends cached telemetry when connectivity is restored.\n */\n private async sendToOtherTransports(items: TransportItem[]): Promise<boolean> {\n if (this.otherTransports.length === 0) {\n this.logWarn('No other transports registered for offline replay');\n return false;\n }\n\n try {\n for (const transport of this.otherTransports) {\n await transport.send(items);\n }\n return true;\n } catch (error) {\n this.logError('Failed to send cached payload to transports', error);\n return false;\n }\n }\n}\n"]}
|
|
@@ -55,8 +55,7 @@ var DEFAULT_STORAGE_KEY = 'faro_persisted_user';
|
|
|
55
55
|
* Stores user information persistently so it can be restored on app restart.
|
|
56
56
|
* This ensures early telemetry events include user identification.
|
|
57
57
|
*
|
|
58
|
-
*
|
|
59
|
-
* - Uses AsyncStorage for persistence (matching Flutter's SharedPreferences)
|
|
58
|
+
* Uses AsyncStorage for persistent user data across app sessions.
|
|
60
59
|
* - Stores user as JSON
|
|
61
60
|
* - Handles null/cleared users
|
|
62
61
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserPersistence.js","sourceRoot":"","sources":["../../../src/userPersistence/UserPersistence.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"UserPersistence.js","sourceRoot":"","sources":["../../../src/userPersistence/UserPersistence.ts"],"names":[],"mappings":"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","sourcesContent":["import AsyncStorage from '@react-native-async-storage/async-storage';\n\nimport type { MetaUser } from '@grafana/faro-core';\n\nimport type { UserPersistence, UserPersistenceOptions } from './types';\n\n/**\n * Default storage key for user data.\n */\nconst DEFAULT_STORAGE_KEY = 'faro_persisted_user';\n\n/**\n * UserPersistence implementation using AsyncStorage.\n *\n * Stores user information persistently so it can be restored on app restart.\n * This ensures early telemetry events include user identification.\n *\n * Uses AsyncStorage for persistent user data across app sessions.\n * - Stores user as JSON\n * - Handles null/cleared users\n *\n * @example\n * ```typescript\n * import { createUserPersistence } from '@grafana/faro-react-native';\n *\n * // Load user on app start\n * const persistence = createUserPersistence();\n * const user = await persistence.loadUser();\n *\n * if (user) {\n * faro.api.setUser(user);\n * }\n *\n * // Save user when logged in\n * const loggedInUser = { id: '123', email: 'user@example.com' };\n * await persistence.saveUser(loggedInUser);\n *\n * // Clear on logout\n * await persistence.clearUser();\n * ```\n */\nexport class AsyncStorageUserPersistence implements UserPersistence {\n private readonly storageKey: string;\n\n constructor(options: UserPersistenceOptions = {}) {\n this.storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n }\n\n async loadUser(): Promise<MetaUser | null> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n if (userJson === null) {\n return null;\n }\n\n const userData = JSON.parse(userJson);\n if (!this.isValidMetaUser(userData)) {\n return null;\n }\n\n return userData;\n } catch {\n return null;\n }\n }\n\n async saveUser(user: MetaUser | null): Promise<void> {\n try {\n if (user === null || this.isCleared(user)) {\n await this.clearUser();\n return;\n }\n\n const userJson = JSON.stringify(user);\n await AsyncStorage.setItem(this.storageKey, userJson);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async clearUser(): Promise<void> {\n try {\n await AsyncStorage.removeItem(this.storageKey);\n } catch {\n // Log failure but don't throw\n }\n }\n\n async hasPersistedUser(): Promise<boolean> {\n try {\n const userJson = await AsyncStorage.getItem(this.storageKey);\n return userJson !== null;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if user is cleared (all fields empty/undefined).\n */\n private isCleared(user: MetaUser): boolean {\n return !user.id && !user.email && !user.username && !user.fullName && !user.roles;\n }\n\n /**\n * Validate that the parsed object is a valid MetaUser.\n */\n private isValidMetaUser(obj: unknown): obj is MetaUser {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n // MetaUser has optional string fields, so any object is technically valid\n // We just need to make sure it's an object\n return true;\n }\n}\n\n/**\n * Factory function to create a UserPersistence instance.\n */\nexport function createUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n return new AsyncStorageUserPersistence(options);\n}\n\n/**\n * Global user persistence instance.\n */\nlet globalUserPersistence: UserPersistence | null = null;\n\n/**\n * Initialize the global user persistence.\n */\nexport function initializeUserPersistence(options: UserPersistenceOptions = {}): UserPersistence {\n globalUserPersistence = createUserPersistence(options);\n return globalUserPersistence;\n}\n\n/**\n * Get the global user persistence instance.\n */\nexport function getUserPersistence(): UserPersistence | null {\n return globalUserPersistence;\n}\n\n/**\n * Set a custom user persistence instance.\n */\nexport function setUserPersistence(persistence: UserPersistence | null): void {\n globalUserPersistence = persistence;\n}\n"]}
|
|
@@ -19,8 +19,7 @@ function toRegExpArray(patterns) {
|
|
|
19
19
|
/**
|
|
20
20
|
* Returns the default set of instrumentations for React Native.
|
|
21
21
|
*
|
|
22
|
-
* Reads all options from the Faro config (single source of truth)
|
|
23
|
-
* Property names are aligned with Flutter SDK FaroConfig:
|
|
22
|
+
* Reads all options from the Faro config (single source of truth):
|
|
24
23
|
* - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals
|
|
25
24
|
* - enableCrashReporting, enableErrorReporting
|
|
26
25
|
* - fetchVitalsInterval, ignoreUrls
|
|
@@ -40,7 +39,6 @@ function toRegExpArray(patterns) {
|
|
|
40
39
|
* ```
|
|
41
40
|
*/
|
|
42
41
|
export function getRNInstrumentations(config = {}) {
|
|
43
|
-
// Aligned with Flutter SDK FaroConfig defaults
|
|
44
42
|
const {
|
|
45
43
|
// Error & crash tracking
|
|
46
44
|
enableErrorReporting = true, enableCrashReporting = false, anrTracking = false, anrOptions = {},
|
|
@@ -53,21 +51,21 @@ export function getRNInstrumentations(config = {}) {
|
|
|
53
51
|
// Tracing
|
|
54
52
|
enableTracing = false, tracingOptions = {}, } = config;
|
|
55
53
|
const instrumentations = [];
|
|
56
|
-
// Error reporting
|
|
54
|
+
// Error reporting
|
|
57
55
|
if (enableErrorReporting) {
|
|
58
56
|
instrumentations.push(new ErrorsInstrumentation({
|
|
59
57
|
releaseBundleFilename: config.releaseBundleFilename,
|
|
60
58
|
}));
|
|
61
59
|
}
|
|
62
|
-
// Console capture
|
|
60
|
+
// Console capture
|
|
63
61
|
if (enableConsoleCapture) {
|
|
64
62
|
instrumentations.push(new ConsoleInstrumentation());
|
|
65
63
|
}
|
|
66
|
-
// Sessions
|
|
64
|
+
// Sessions
|
|
67
65
|
instrumentations.push(new SessionInstrumentation());
|
|
68
|
-
// Views
|
|
66
|
+
// Views
|
|
69
67
|
instrumentations.push(new ViewInstrumentation());
|
|
70
|
-
// App state
|
|
68
|
+
// App state
|
|
71
69
|
instrumentations.push(new AppStateInstrumentation());
|
|
72
70
|
// User actions - enabled by default, opt-out via enableUserActions
|
|
73
71
|
if (enableUserActions) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAIxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D,mGAAmG;AACnG,SAAS,aAAa,CAAC,QAAkB;IACvC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\n\nimport type { Instrumentation, Patterns } from '@grafana/faro-core';\n\nimport { ANRInstrumentation } from '../instrumentations/anr';\nimport { AppStateInstrumentation } from '../instrumentations/appState';\nimport { ConsoleInstrumentation } from '../instrumentations/console';\nimport { CrashReportingInstrumentation } from '../instrumentations/crashReporting';\nimport { ErrorsInstrumentation } from '../instrumentations/errors';\nimport { FrameMonitoringInstrumentation } from '../instrumentations/frameMonitoring';\nimport { HttpInstrumentation } from '../instrumentations/http';\nimport { PerformanceInstrumentation } from '../instrumentations/performance';\nimport { SessionInstrumentation } from '../instrumentations/session';\nimport { StartupInstrumentation } from '../instrumentations/startup';\nimport { UserActionInstrumentation } from '../instrumentations/userActions';\nimport { ViewInstrumentation } from '../instrumentations/view';\nimport { XHRInstrumentation } from '../instrumentations/xhr';\n\nimport type { ReactNativeConfig } from './types';\n\n/** Convert Patterns (string | RegExp)[] to RegExp[] for instrumentations that require RegExp[]. */\nfunction toRegExpArray(patterns: Patterns): RegExp[] {\n return patterns.map((p) => (typeof p === 'string' ? new RegExp(p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')) : p));\n}\n\n/**\n * Returns the default set of instrumentations for React Native.\n *\n * Reads all options from the Faro config (single source of truth):\n * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals\n * - enableCrashReporting, enableErrorReporting\n * - fetchVitalsInterval, ignoreUrls\n *\n * @example\n * ```ts\n * const config: ReactNativeConfig = {\n * app: { name: 'my-app', version: '1.0.0' },\n * cpuUsageVitals: true,\n * memoryUsageVitals: true,\n * anrTracking: true,\n * refreshRateVitals: true,\n * enableCrashReporting: true,\n * fetchVitalsInterval: 30000,\n * instrumentations: getRNInstrumentations(config),\n * };\n * ```\n */\nexport function getRNInstrumentations(config: Partial<ReactNativeConfig> = {}): Instrumentation[] {\n const {\n // Error & crash tracking\n enableErrorReporting = true,\n enableCrashReporting = false,\n anrTracking = false,\n anrOptions = {},\n\n // Performance vitals\n cpuUsageVitals = true,\n memoryUsageVitals = true,\n refreshRateVitals = false,\n fetchVitalsInterval = 30000,\n frameMonitoringOptions = {},\n\n // Network\n ignoreUrls = [],\n enableHttpInstrumentation = {},\n\n // Console and user actions\n enableConsoleCapture = true,\n enableUserActions = true,\n\n // Tracing\n enableTracing = false,\n tracingOptions = {},\n } = config;\n\n const instrumentations: Instrumentation[] = [];\n\n // Error reporting\n if (enableErrorReporting) {\n instrumentations.push(\n new ErrorsInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n // Console capture\n if (enableConsoleCapture) {\n instrumentations.push(new ConsoleInstrumentation());\n }\n\n // Sessions\n instrumentations.push(new SessionInstrumentation());\n\n // Views\n instrumentations.push(new ViewInstrumentation());\n\n // App state\n instrumentations.push(new AppStateInstrumentation());\n\n // User actions - enabled by default, opt-out via enableUserActions\n if (enableUserActions) {\n instrumentations.push(new UserActionInstrumentation());\n }\n\n // HTTP/XHR tracking: when tracing is enabled, TracingInstrumentation patches fetch and XHR.\n // When tracing is disabled, add HttpInstrumentation and/or XHRInstrumentation per enableHttpInstrumentation.\n if (!enableTracing) {\n const { fetch: enableFetch = true, xhr: enableXhr = true } = enableHttpInstrumentation;\n const ignoredUrlsRegExp = toRegExpArray(ignoreUrls);\n if (enableFetch) {\n instrumentations.push(new HttpInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n if (enableXhr) {\n instrumentations.push(new XHRInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n }\n\n // Performance vitals (CPU/memory) - only add if at least one metric is enabled\n if (cpuUsageVitals || memoryUsageVitals) {\n const perfInstrumentation = new PerformanceInstrumentation({\n memoryUsageVitals,\n cpuUsageVitals,\n fetchVitalsInterval,\n });\n instrumentations.push(perfInstrumentation);\n }\n\n // Startup tracking - always enabled\n instrumentations.push(new StartupInstrumentation());\n\n // Frame monitoring: enabled when refreshRateVitals is true\n // The instrumentation reads refreshRateVitals from faro.config (single source of truth)\n if (refreshRateVitals) {\n instrumentations.push(new FrameMonitoringInstrumentation(frameMonitoringOptions));\n }\n\n // ANR detection (Android only)\n if (anrTracking && Platform.OS === 'android') {\n instrumentations.push(new ANRInstrumentation(anrOptions));\n }\n\n // Crash reporting\n if (enableCrashReporting) {\n instrumentations.push(\n new CrashReportingInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n if (enableTracing) {\n try {\n const { TracingInstrumentation } = require('@grafana/faro-react-native-tracing');\n instrumentations.push(new TracingInstrumentation(tracingOptions));\n } catch {\n console.warn(\n '[Faro] enableTracing is true but @grafana/faro-react-native-tracing is not installed. ' +\n 'Add it to use tracing: yarn add @grafana/faro-react-native-tracing'\n );\n }\n }\n\n return instrumentations;\n}\n"]}
|
|
@@ -101,12 +101,12 @@ export function makeRNConfig(config, preloadedMobileMeta, appSymbolsBundleId) {
|
|
|
101
101
|
const instrumentations = buildInstrumentations(config);
|
|
102
102
|
const installationId = (_c = config.app.installationId) !== null && _c !== void 0 ? _c : preloadedAppMeta === null || preloadedAppMeta === void 0 ? void 0 : preloadedAppMeta.installationId;
|
|
103
103
|
const releaseBundleFilename = config.releaseBundleFilename;
|
|
104
|
-
// Merge bundleId (from config, Metro, or DeviceInfo) with preloaded app meta
|
|
105
104
|
const bundleIdValue = resolveAppBundleId(config.app, (_d = config.app) === null || _d === void 0 ? void 0 : _d.name, appSymbolsBundleId);
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
const app = Object.assign(Object.assign(Object.assign(Object.assign({}, preloadedAppMeta), config.app), (installationId && { installationId })), (bundleIdValue && { bundleId: bundleIdValue }));
|
|
106
|
+
// Core merges metadata shallowly. Supply the complete app object so native
|
|
107
|
+
// metadata cannot replace configured fields such as version and environment.
|
|
108
|
+
const appMetasIfPresent = preloadedAppMeta || bundleIdValue ? [{ app }] : [];
|
|
109
|
+
return Object.assign(Object.assign({ app }, (preloadedMobileMeta != null && {
|
|
110
110
|
preloadedMobileMeta: preloadedMobileMeta.meta,
|
|
111
111
|
preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,
|
|
112
112
|
})), { dedupe: (_e = config.dedupe) !== null && _e !== void 0 ? _e : true, globalObjectKey: (_f = config.globalObjectKey) !== null && _f !== void 0 ? _f : defaultGlobalObjectKey, internalLoggerLevel: (_g = config.internalLoggerLevel) !== null && _g !== void 0 ? _g : InternalLoggerLevel.ERROR, isolate: (_h = config.isolate) !== null && _h !== void 0 ? _h : false, parseStacktrace: (_j = config.parseStacktrace) !== null && _j !== void 0 ? _j : createParseStacktrace(releaseBundleFilename), paused: (_k = config.paused) !== null && _k !== void 0 ? _k : false, preventGlobalExposure: (_l = config.preventGlobalExposure) !== null && _l !== void 0 ? _l : false, unpatchedConsole: (_m = config.unpatchedConsole) !== null && _m !== void 0 ? _m : defaultUnpatchedConsole, batching: {
|