@mobileai/react-native 0.9.17 → 0.9.19
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/LICENSE +28 -20
- package/MobileAIFloatingOverlay.podspec +25 -0
- package/android/build.gradle +61 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/mobileai/overlay/FloatingOverlayView.kt +151 -0
- package/android/src/main/java/com/mobileai/overlay/MobileAIOverlayPackage.kt +23 -0
- package/android/src/newarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +45 -0
- package/android/src/oldarch/com/mobileai/overlay/FloatingOverlayViewManager.kt +29 -0
- package/ios/MobileAIFloatingOverlayComponentView.mm +73 -0
- package/lib/module/components/AIAgent.js +902 -136
- package/lib/module/components/AIConsentDialog.js +439 -0
- package/lib/module/components/AgentChatBar.js +828 -134
- package/lib/module/components/AgentOverlay.js +2 -1
- package/lib/module/components/DiscoveryTooltip.js +21 -9
- package/lib/module/components/FloatingOverlayWrapper.js +108 -0
- package/lib/module/components/Icons.js +123 -0
- package/lib/module/config/endpoints.js +12 -2
- package/lib/module/core/AgentRuntime.js +373 -27
- package/lib/module/core/FiberAdapter.js +56 -0
- package/lib/module/core/FiberTreeWalker.js +186 -80
- package/lib/module/core/IdleDetector.js +19 -0
- package/lib/module/core/NativeAlertInterceptor.js +191 -0
- package/lib/module/core/systemPrompt.js +203 -45
- package/lib/module/index.js +3 -0
- package/lib/module/providers/GeminiProvider.js +72 -56
- package/lib/module/providers/ProviderFactory.js +6 -2
- package/lib/module/services/AudioInputService.js +3 -12
- package/lib/module/services/AudioOutputService.js +1 -13
- package/lib/module/services/ConversationService.js +166 -0
- package/lib/module/services/MobileAIKnowledgeRetriever.js +41 -0
- package/lib/module/services/VoiceService.js +29 -8
- package/lib/module/services/telemetry/MobileAI.js +44 -0
- package/lib/module/services/telemetry/TelemetryService.js +13 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js +44 -18
- package/lib/module/specs/FloatingOverlayNativeComponent.ts +19 -0
- package/lib/module/support/CSATSurvey.js +95 -12
- package/lib/module/support/EscalationSocket.js +70 -1
- package/lib/module/support/ReportedIssueEventSource.js +148 -0
- package/lib/module/support/escalateTool.js +4 -2
- package/lib/module/support/index.js +1 -0
- package/lib/module/support/reportIssueTool.js +127 -0
- package/lib/module/support/supportPrompt.js +77 -9
- package/lib/module/tools/guideTool.js +2 -1
- package/lib/module/tools/longPressTool.js +4 -3
- package/lib/module/tools/pickerTool.js +6 -4
- package/lib/module/tools/tapTool.js +12 -3
- package/lib/module/tools/typeTool.js +19 -10
- package/lib/module/utils/logger.js +175 -6
- package/lib/typescript/react-native.config.d.ts +11 -0
- package/lib/typescript/src/components/AIAgent.d.ts +28 -2
- package/lib/typescript/src/components/AIConsentDialog.d.ts +153 -0
- package/lib/typescript/src/components/AgentChatBar.d.ts +15 -2
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts +3 -1
- package/lib/typescript/src/components/FloatingOverlayWrapper.d.ts +51 -0
- package/lib/typescript/src/components/Icons.d.ts +8 -0
- package/lib/typescript/src/config/endpoints.d.ts +5 -3
- package/lib/typescript/src/core/AgentRuntime.d.ts +4 -0
- package/lib/typescript/src/core/FiberAdapter.d.ts +25 -0
- package/lib/typescript/src/core/FiberTreeWalker.d.ts +2 -0
- package/lib/typescript/src/core/IdleDetector.d.ts +11 -0
- package/lib/typescript/src/core/NativeAlertInterceptor.d.ts +55 -0
- package/lib/typescript/src/core/types.d.ts +106 -1
- package/lib/typescript/src/index.d.ts +9 -4
- package/lib/typescript/src/providers/GeminiProvider.d.ts +6 -5
- package/lib/typescript/src/services/ConversationService.d.ts +55 -0
- package/lib/typescript/src/services/MobileAIKnowledgeRetriever.d.ts +9 -0
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts +7 -0
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts +1 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts +9 -6
- package/lib/typescript/src/services/telemetry/types.d.ts +3 -1
- package/lib/typescript/src/specs/FloatingOverlayNativeComponent.d.ts +17 -0
- package/lib/typescript/src/support/EscalationSocket.d.ts +17 -0
- package/lib/typescript/src/support/ReportedIssueEventSource.d.ts +24 -0
- package/lib/typescript/src/support/escalateTool.d.ts +5 -0
- package/lib/typescript/src/support/index.d.ts +2 -1
- package/lib/typescript/src/support/reportIssueTool.d.ts +20 -0
- package/lib/typescript/src/support/types.d.ts +56 -1
- package/lib/typescript/src/utils/logger.d.ts +15 -0
- package/package.json +20 -9
- package/react-native.config.js +12 -0
- package/lib/module/__cli_tmp__.js.map +0 -1
- package/lib/module/components/AIAgent.js.map +0 -1
- package/lib/module/components/AIZone.js.map +0 -1
- package/lib/module/components/AgentChatBar.js.map +0 -1
- package/lib/module/components/AgentErrorBoundary.js.map +0 -1
- package/lib/module/components/AgentOverlay.js.map +0 -1
- package/lib/module/components/DiscoveryTooltip.js.map +0 -1
- package/lib/module/components/HighlightOverlay.js.map +0 -1
- package/lib/module/components/Icons.js.map +0 -1
- package/lib/module/components/ProactiveHint.js.map +0 -1
- package/lib/module/components/cards/InfoCard.js.map +0 -1
- package/lib/module/components/cards/ReviewSummary.js.map +0 -1
- package/lib/module/config/endpoints.js.map +0 -1
- package/lib/module/core/ActionRegistry.js.map +0 -1
- package/lib/module/core/AgentRuntime.js.map +0 -1
- package/lib/module/core/FiberTreeWalker.js.map +0 -1
- package/lib/module/core/IdleDetector.js.map +0 -1
- package/lib/module/core/MCPBridge.js.map +0 -1
- package/lib/module/core/ScreenDehydrator.js.map +0 -1
- package/lib/module/core/ZoneRegistry.js.map +0 -1
- package/lib/module/core/systemPrompt.js.map +0 -1
- package/lib/module/core/types.js.map +0 -1
- package/lib/module/hooks/useAction.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/plugin/withAppIntents.js.map +0 -1
- package/lib/module/providers/GeminiProvider.js.map +0 -1
- package/lib/module/providers/OpenAIProvider.js.map +0 -1
- package/lib/module/providers/ProviderFactory.js.map +0 -1
- package/lib/module/services/AudioInputService.js.map +0 -1
- package/lib/module/services/AudioOutputService.js.map +0 -1
- package/lib/module/services/KnowledgeBaseService.js.map +0 -1
- package/lib/module/services/VoiceService.js.map +0 -1
- package/lib/module/services/flags/FlagService.js.map +0 -1
- package/lib/module/services/telemetry/MobileAI.js.map +0 -1
- package/lib/module/services/telemetry/PiiScrubber.js.map +0 -1
- package/lib/module/services/telemetry/TelemetryService.js.map +0 -1
- package/lib/module/services/telemetry/TouchAutoCapture.js.map +0 -1
- package/lib/module/services/telemetry/device.js.map +0 -1
- package/lib/module/services/telemetry/deviceMetadata.js.map +0 -1
- package/lib/module/services/telemetry/index.js.map +0 -1
- package/lib/module/services/telemetry/types.js.map +0 -1
- package/lib/module/support/CSATSurvey.js.map +0 -1
- package/lib/module/support/EscalationEventSource.js.map +0 -1
- package/lib/module/support/EscalationSocket.js.map +0 -1
- package/lib/module/support/SupportChatModal.js.map +0 -1
- package/lib/module/support/SupportGreeting.js.map +0 -1
- package/lib/module/support/TicketStore.js.map +0 -1
- package/lib/module/support/escalateTool.js.map +0 -1
- package/lib/module/support/index.js.map +0 -1
- package/lib/module/support/supportPrompt.js.map +0 -1
- package/lib/module/support/types.js.map +0 -1
- package/lib/module/tools/datePickerTool.js.map +0 -1
- package/lib/module/tools/guideTool.js.map +0 -1
- package/lib/module/tools/index.js.map +0 -1
- package/lib/module/tools/keyboardTool.js.map +0 -1
- package/lib/module/tools/longPressTool.js.map +0 -1
- package/lib/module/tools/pickerTool.js.map +0 -1
- package/lib/module/tools/restoreTool.js.map +0 -1
- package/lib/module/tools/scrollTool.js.map +0 -1
- package/lib/module/tools/simplifyTool.js.map +0 -1
- package/lib/module/tools/sliderTool.js.map +0 -1
- package/lib/module/tools/tapTool.js.map +0 -1
- package/lib/module/tools/typeTool.js.map +0 -1
- package/lib/module/tools/types.js.map +0 -1
- package/lib/module/types/jsx.d.js.map +0 -1
- package/lib/module/utils/audioUtils.js.map +0 -1
- package/lib/module/utils/logger.js.map +0 -1
- package/lib/typescript/babel.config.d.ts.map +0 -1
- package/lib/typescript/bin/generate-map.d.cts.map +0 -1
- package/lib/typescript/eslint.config.d.mts.map +0 -1
- package/lib/typescript/generate-map.d.ts.map +0 -1
- package/lib/typescript/src/__cli_tmp__.d.ts.map +0 -1
- package/lib/typescript/src/components/AIAgent.d.ts.map +0 -1
- package/lib/typescript/src/components/AIZone.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentChatBar.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentErrorBoundary.d.ts.map +0 -1
- package/lib/typescript/src/components/AgentOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/DiscoveryTooltip.d.ts.map +0 -1
- package/lib/typescript/src/components/HighlightOverlay.d.ts.map +0 -1
- package/lib/typescript/src/components/Icons.d.ts.map +0 -1
- package/lib/typescript/src/components/ProactiveHint.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/InfoCard.d.ts.map +0 -1
- package/lib/typescript/src/components/cards/ReviewSummary.d.ts.map +0 -1
- package/lib/typescript/src/config/endpoints.d.ts.map +0 -1
- package/lib/typescript/src/core/ActionRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/AgentRuntime.d.ts.map +0 -1
- package/lib/typescript/src/core/FiberTreeWalker.d.ts.map +0 -1
- package/lib/typescript/src/core/IdleDetector.d.ts.map +0 -1
- package/lib/typescript/src/core/MCPBridge.d.ts.map +0 -1
- package/lib/typescript/src/core/ScreenDehydrator.d.ts.map +0 -1
- package/lib/typescript/src/core/ZoneRegistry.d.ts.map +0 -1
- package/lib/typescript/src/core/systemPrompt.d.ts.map +0 -1
- package/lib/typescript/src/core/types.d.ts.map +0 -1
- package/lib/typescript/src/hooks/useAction.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/plugin/withAppIntents.d.ts.map +0 -1
- package/lib/typescript/src/providers/GeminiProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/OpenAIProvider.d.ts.map +0 -1
- package/lib/typescript/src/providers/ProviderFactory.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioInputService.d.ts.map +0 -1
- package/lib/typescript/src/services/AudioOutputService.d.ts.map +0 -1
- package/lib/typescript/src/services/KnowledgeBaseService.d.ts.map +0 -1
- package/lib/typescript/src/services/VoiceService.d.ts.map +0 -1
- package/lib/typescript/src/services/flags/FlagService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/MobileAI.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/PiiScrubber.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TelemetryService.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/TouchAutoCapture.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/device.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/deviceMetadata.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/index.d.ts.map +0 -1
- package/lib/typescript/src/services/telemetry/types.d.ts.map +0 -1
- package/lib/typescript/src/support/CSATSurvey.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationEventSource.d.ts.map +0 -1
- package/lib/typescript/src/support/EscalationSocket.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportChatModal.d.ts.map +0 -1
- package/lib/typescript/src/support/SupportGreeting.d.ts.map +0 -1
- package/lib/typescript/src/support/TicketStore.d.ts.map +0 -1
- package/lib/typescript/src/support/escalateTool.d.ts.map +0 -1
- package/lib/typescript/src/support/index.d.ts.map +0 -1
- package/lib/typescript/src/support/supportPrompt.d.ts.map +0 -1
- package/lib/typescript/src/support/types.d.ts.map +0 -1
- package/lib/typescript/src/tools/datePickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/guideTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/index.d.ts.map +0 -1
- package/lib/typescript/src/tools/keyboardTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/longPressTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/pickerTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/restoreTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/scrollTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/simplifyTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/sliderTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/tapTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/typeTool.d.ts.map +0 -1
- package/lib/typescript/src/tools/types.d.ts.map +0 -1
- package/lib/typescript/src/utils/audioUtils.d.ts.map +0 -1
- package/lib/typescript/src/utils/logger.d.ts.map +0 -1
- package/src/__cli_tmp__.tsx +0 -9
- package/src/cli/analyzers/chain-analyzer.ts +0 -183
- package/src/cli/extractors/ai-extractor.ts +0 -6
- package/src/cli/extractors/ast-extractor.ts +0 -551
- package/src/cli/generate-intents.ts +0 -140
- package/src/cli/generate-map.ts +0 -121
- package/src/cli/generate-swift.ts +0 -116
- package/src/cli/scanners/expo-scanner.ts +0 -203
- package/src/cli/scanners/rn-scanner.ts +0 -445
- package/src/components/AIAgent.tsx +0 -1716
- package/src/components/AIZone.tsx +0 -147
- package/src/components/AgentChatBar.tsx +0 -1143
- package/src/components/AgentErrorBoundary.tsx +0 -78
- package/src/components/AgentOverlay.tsx +0 -73
- package/src/components/DiscoveryTooltip.tsx +0 -148
- package/src/components/HighlightOverlay.tsx +0 -136
- package/src/components/Icons.tsx +0 -253
- package/src/components/ProactiveHint.tsx +0 -145
- package/src/components/cards/InfoCard.tsx +0 -58
- package/src/components/cards/ReviewSummary.tsx +0 -76
- package/src/config/endpoints.ts +0 -22
- package/src/core/ActionRegistry.ts +0 -105
- package/src/core/AgentRuntime.ts +0 -1471
- package/src/core/FiberTreeWalker.ts +0 -930
- package/src/core/IdleDetector.ts +0 -72
- package/src/core/MCPBridge.ts +0 -163
- package/src/core/ScreenDehydrator.ts +0 -53
- package/src/core/ZoneRegistry.ts +0 -44
- package/src/core/systemPrompt.ts +0 -431
- package/src/core/types.ts +0 -521
- package/src/hooks/useAction.ts +0 -182
- package/src/index.ts +0 -83
- package/src/plugin/withAppIntents.ts +0 -98
- package/src/providers/GeminiProvider.ts +0 -357
- package/src/providers/OpenAIProvider.ts +0 -379
- package/src/providers/ProviderFactory.ts +0 -36
- package/src/services/AudioInputService.ts +0 -226
- package/src/services/AudioOutputService.ts +0 -236
- package/src/services/KnowledgeBaseService.ts +0 -156
- package/src/services/VoiceService.ts +0 -451
- package/src/services/flags/FlagService.ts +0 -137
- package/src/services/telemetry/MobileAI.ts +0 -66
- package/src/services/telemetry/PiiScrubber.ts +0 -17
- package/src/services/telemetry/TelemetryService.ts +0 -323
- package/src/services/telemetry/TouchAutoCapture.ts +0 -165
- package/src/services/telemetry/device.ts +0 -93
- package/src/services/telemetry/deviceMetadata.ts +0 -13
- package/src/services/telemetry/index.ts +0 -13
- package/src/services/telemetry/types.ts +0 -75
- package/src/support/CSATSurvey.tsx +0 -304
- package/src/support/EscalationEventSource.ts +0 -190
- package/src/support/EscalationSocket.ts +0 -152
- package/src/support/SupportChatModal.tsx +0 -563
- package/src/support/SupportGreeting.tsx +0 -161
- package/src/support/TicketStore.ts +0 -100
- package/src/support/escalateTool.ts +0 -174
- package/src/support/index.ts +0 -29
- package/src/support/supportPrompt.ts +0 -55
- package/src/support/types.ts +0 -155
- package/src/tools/datePickerTool.ts +0 -60
- package/src/tools/guideTool.ts +0 -76
- package/src/tools/index.ts +0 -20
- package/src/tools/keyboardTool.ts +0 -30
- package/src/tools/longPressTool.ts +0 -61
- package/src/tools/pickerTool.ts +0 -115
- package/src/tools/restoreTool.ts +0 -33
- package/src/tools/scrollTool.ts +0 -156
- package/src/tools/simplifyTool.ts +0 -33
- package/src/tools/sliderTool.ts +0 -65
- package/src/tools/tapTool.ts +0 -93
- package/src/tools/typeTool.ts +0 -113
- package/src/tools/types.ts +0 -58
- package/src/types/jsx.d.ts +0 -20
- package/src/utils/audioUtils.ts +0 -54
- package/src/utils/logger.ts +0 -38
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TelemetryService — Batches and sends analytics events to MobileAI Cloud.
|
|
3
|
-
*
|
|
4
|
-
* Features:
|
|
5
|
-
* - Event batching (flush every N seconds or N events)
|
|
6
|
-
* - Offline queue with retry on reconnect
|
|
7
|
-
* - Lightweight — no native dependencies
|
|
8
|
-
* - Opt-in only (requires analyticsKey or analyticsProxyUrl)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { AppState, Platform } from 'react-native';
|
|
12
|
-
import { logger } from '../../utils/logger';
|
|
13
|
-
import { ENDPOINTS } from '../../config/endpoints';
|
|
14
|
-
import type {
|
|
15
|
-
TelemetryEvent,
|
|
16
|
-
TelemetryBatch,
|
|
17
|
-
TelemetryConfig,
|
|
18
|
-
} from './types';
|
|
19
|
-
import { scrubPII } from './PiiScrubber';
|
|
20
|
-
import { FlagService } from '../flags/FlagService';
|
|
21
|
-
|
|
22
|
-
// Optional: AsyncStorage for offline event persistence
|
|
23
|
-
// SDK works without it — just loses crash recovery for queued events
|
|
24
|
-
let _asyncStorage: any = null;
|
|
25
|
-
let _asyncStorageLoaded = false;
|
|
26
|
-
|
|
27
|
-
function loadAsyncStorage(): any {
|
|
28
|
-
if (_asyncStorageLoaded) return _asyncStorage;
|
|
29
|
-
_asyncStorageLoaded = true;
|
|
30
|
-
try {
|
|
31
|
-
// Suppress the RN red box that AsyncStorage triggers when its native module
|
|
32
|
-
// isn't linked ("NativeModule: AsyncStorage is null").
|
|
33
|
-
const origError = console.error;
|
|
34
|
-
console.error = (...args: unknown[]) => {
|
|
35
|
-
const msg = args[0];
|
|
36
|
-
if (typeof msg === 'string' && msg.includes('AsyncStorage')) return;
|
|
37
|
-
origError.apply(console, args);
|
|
38
|
-
};
|
|
39
|
-
try {
|
|
40
|
-
const mod = require('@react-native-async-storage/async-storage');
|
|
41
|
-
_asyncStorage = mod.default ?? mod;
|
|
42
|
-
} finally {
|
|
43
|
-
console.error = origError;
|
|
44
|
-
}
|
|
45
|
-
// Verify the native module actually works by checking for the native bridge
|
|
46
|
-
if (!_asyncStorage || typeof _asyncStorage.getItem !== 'function') {
|
|
47
|
-
_asyncStorage = null;
|
|
48
|
-
}
|
|
49
|
-
} catch {
|
|
50
|
-
// Not installed — offline queue persistence disabled
|
|
51
|
-
}
|
|
52
|
-
return _asyncStorage;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ─── Constants ─────────────────────────────────────────────────
|
|
56
|
-
|
|
57
|
-
const CLOUD_API_URL = ENDPOINTS.telemetryIngest;
|
|
58
|
-
const STORAGE_KEY = '@mobileai/telemetry_queue';
|
|
59
|
-
const DEFAULT_FLUSH_INTERVAL_MS = 30_000;
|
|
60
|
-
const DEFAULT_MAX_BATCH_SIZE = 50;
|
|
61
|
-
const SDK_VERSION = '0.10.0';
|
|
62
|
-
const LOG_TAG = 'Telemetry';
|
|
63
|
-
|
|
64
|
-
// ─── Utility ───────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
function generateSessionId(): string {
|
|
67
|
-
return `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
import { getDeviceId } from './device';
|
|
71
|
-
|
|
72
|
-
// ─── Service ───────────────────────────────────────────────────
|
|
73
|
-
|
|
74
|
-
export class TelemetryService {
|
|
75
|
-
private queue: TelemetryEvent[] = [];
|
|
76
|
-
private config: TelemetryConfig;
|
|
77
|
-
private sessionId: string;
|
|
78
|
-
private currentScreen = 'Unknown';
|
|
79
|
-
private screenFlow: string[] = [];
|
|
80
|
-
private flushTimer: ReturnType<typeof setInterval> | null = null;
|
|
81
|
-
private isFlushing = false;
|
|
82
|
-
private appStateSubscription: ReturnType<typeof AppState.addEventListener> | null = null;
|
|
83
|
-
|
|
84
|
-
get screen(): string {
|
|
85
|
-
return this.currentScreen;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
getScreenFlow(): string[] {
|
|
89
|
-
return [...this.screenFlow];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* True while the AI agent is executing a tool (tap, type, navigate, etc.).
|
|
94
|
-
* The touch interceptor checks this flag to avoid double-counting AI actions
|
|
95
|
-
* as human interactions. Agent steps are already tracked as agent_step events.
|
|
96
|
-
*/
|
|
97
|
-
isAgentActing = false;
|
|
98
|
-
|
|
99
|
-
public flags: FlagService;
|
|
100
|
-
|
|
101
|
-
/** Set by AgentRuntime before/after each tool execution. */
|
|
102
|
-
setAgentActing(active: boolean): void {
|
|
103
|
-
this.isAgentActing = active;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
constructor(config: TelemetryConfig) {
|
|
107
|
-
this.config = config;
|
|
108
|
-
this.sessionId = generateSessionId();
|
|
109
|
-
|
|
110
|
-
// Extract base URL for flags API (e.g. drop /v1/events)
|
|
111
|
-
let baseUrl = new URL(ENDPOINTS.escalation).origin;
|
|
112
|
-
try {
|
|
113
|
-
if (config.analyticsProxyUrl) {
|
|
114
|
-
baseUrl = new URL(config.analyticsProxyUrl).origin;
|
|
115
|
-
}
|
|
116
|
-
} catch {}
|
|
117
|
-
this.flags = new FlagService(baseUrl);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// ─── Lifecycle ──────────────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
/** Start the telemetry service (call on mount) */
|
|
123
|
-
async start(): Promise<void> {
|
|
124
|
-
if (!this.isEnabled()) {
|
|
125
|
-
logger.debug(LOG_TAG, 'Disabled — no analyticsKey or proxyUrl');
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Restore queued events from previous session
|
|
130
|
-
await this.restoreQueue();
|
|
131
|
-
|
|
132
|
-
// Fetch feature flags asynchronously (do not block startup)
|
|
133
|
-
if (this.config.analyticsKey) {
|
|
134
|
-
this.flags.fetch(this.config.analyticsKey).catch((e) =>
|
|
135
|
-
logger.warn(LOG_TAG, `Could not sync flags: ${e.message}`)
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Start periodic flush
|
|
140
|
-
const interval = this.config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
141
|
-
this.flushTimer = setInterval(() => this.flush(), interval);
|
|
142
|
-
|
|
143
|
-
// Flush on app background
|
|
144
|
-
this.appStateSubscription = AppState.addEventListener(
|
|
145
|
-
'change',
|
|
146
|
-
(state) => {
|
|
147
|
-
if (state === 'background' || state === 'inactive') {
|
|
148
|
-
this.flush();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
// Track session start
|
|
154
|
-
this.track('session_start', {
|
|
155
|
-
device: Platform.OS,
|
|
156
|
-
os: String(Platform.Version),
|
|
157
|
-
sdk_version: SDK_VERSION,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
logger.info(LOG_TAG, `Started (session: ${this.sessionId})`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** Stop the telemetry service (call on unmount) */
|
|
164
|
-
async stop(): Promise<void> {
|
|
165
|
-
if (!this.isEnabled()) return;
|
|
166
|
-
|
|
167
|
-
// Track session end
|
|
168
|
-
this.track('session_end', {
|
|
169
|
-
events_count: this.queue.length,
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// Final flush
|
|
173
|
-
await this.flush();
|
|
174
|
-
|
|
175
|
-
// Cleanup
|
|
176
|
-
if (this.flushTimer) {
|
|
177
|
-
clearInterval(this.flushTimer);
|
|
178
|
-
this.flushTimer = null;
|
|
179
|
-
}
|
|
180
|
-
if (this.appStateSubscription) {
|
|
181
|
-
this.appStateSubscription.remove();
|
|
182
|
-
this.appStateSubscription = null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
logger.info(LOG_TAG, 'Stopped');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// ─── Public API ─────────────────────────────────────────────
|
|
189
|
-
|
|
190
|
-
/** Track an event (auto or custom) */
|
|
191
|
-
track(type: string, data: Record<string, unknown> = {}): void {
|
|
192
|
-
if (!this.isEnabled()) return;
|
|
193
|
-
|
|
194
|
-
// Sanitize any string values in the data payload to remove PII
|
|
195
|
-
const sanitizedData = Object.fromEntries(
|
|
196
|
-
Object.entries(data).map(([k, v]) => [
|
|
197
|
-
k,
|
|
198
|
-
typeof v === 'string' ? scrubPII(v) : v,
|
|
199
|
-
])
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
// Auto-append active feature flags
|
|
203
|
-
sanitizedData.$flags = this.flags.getAllFlags();
|
|
204
|
-
|
|
205
|
-
const event: TelemetryEvent = {
|
|
206
|
-
type,
|
|
207
|
-
data: sanitizedData,
|
|
208
|
-
timestamp: new Date().toISOString(),
|
|
209
|
-
screen: this.currentScreen,
|
|
210
|
-
sessionId: this.sessionId,
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
this.queue.push(event);
|
|
214
|
-
|
|
215
|
-
if (this.config.debug) {
|
|
216
|
-
logger.debug(LOG_TAG, `→ ${type}`, data);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Auto-flush if batch is full
|
|
220
|
-
const maxSize = this.config.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
|
|
221
|
-
if (this.queue.length >= maxSize) {
|
|
222
|
-
this.flush();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/** Update current screen (called by AIAgent on navigation) */
|
|
227
|
-
setScreen(screenName: string): void {
|
|
228
|
-
if (this.currentScreen !== screenName) {
|
|
229
|
-
const prevScreen = this.currentScreen;
|
|
230
|
-
this.currentScreen = screenName;
|
|
231
|
-
this.screenFlow.push(screenName);
|
|
232
|
-
|
|
233
|
-
this.track('screen_view', {
|
|
234
|
-
screen: screenName,
|
|
235
|
-
prev_screen: prevScreen,
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ─── Flush ──────────────────────────────────────────────────
|
|
241
|
-
|
|
242
|
-
/** Send queued events to the cloud API */
|
|
243
|
-
async flush(): Promise<void> {
|
|
244
|
-
if (!this.isEnabled() || this.queue.length === 0 || this.isFlushing) return;
|
|
245
|
-
|
|
246
|
-
this.isFlushing = true;
|
|
247
|
-
const eventsToSend = [...this.queue];
|
|
248
|
-
this.queue = [];
|
|
249
|
-
|
|
250
|
-
try {
|
|
251
|
-
const url = this.config.analyticsProxyUrl ?? CLOUD_API_URL;
|
|
252
|
-
const headers: Record<string, string> = {
|
|
253
|
-
'Content-Type': 'application/json',
|
|
254
|
-
...(this.config.analyticsProxyHeaders ?? {}),
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
const batch: TelemetryBatch = {
|
|
258
|
-
analyticsKey: this.config.analyticsKey ?? '',
|
|
259
|
-
appId: Platform.OS, // Consumer can override via config later
|
|
260
|
-
deviceId: getDeviceId() ?? 'unknown',
|
|
261
|
-
sdkVersion: SDK_VERSION,
|
|
262
|
-
events: eventsToSend,
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const response = await fetch(url, {
|
|
266
|
-
method: 'POST',
|
|
267
|
-
headers,
|
|
268
|
-
body: JSON.stringify(batch),
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
if (!response.ok) {
|
|
272
|
-
throw new Error(`HTTP ${response.status}`);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
logger.info(LOG_TAG, `Flushed ${eventsToSend.length} events`);
|
|
276
|
-
} catch (error: any) {
|
|
277
|
-
// Re-queue failed events for retry
|
|
278
|
-
this.queue = [...eventsToSend, ...this.queue];
|
|
279
|
-
await this.persistQueue();
|
|
280
|
-
|
|
281
|
-
logger.warn(LOG_TAG, `Flush failed (${eventsToSend.length} events re-queued): ${error.message}`);
|
|
282
|
-
} finally {
|
|
283
|
-
this.isFlushing = false;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// ─── Persistence (offline support) ──────────────────────────
|
|
288
|
-
|
|
289
|
-
/** Save queued events to AsyncStorage for crash/restart recovery */
|
|
290
|
-
private async persistQueue(): Promise<void> {
|
|
291
|
-
const storage = loadAsyncStorage();
|
|
292
|
-
if (!storage) return;
|
|
293
|
-
try {
|
|
294
|
-
await storage.setItem(STORAGE_KEY, JSON.stringify(this.queue));
|
|
295
|
-
} catch {
|
|
296
|
-
// AsyncStorage may not be available in all environments
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/** Restore queued events from previous session */
|
|
301
|
-
private async restoreQueue(): Promise<void> {
|
|
302
|
-
const storage = loadAsyncStorage();
|
|
303
|
-
if (!storage) return;
|
|
304
|
-
try {
|
|
305
|
-
const stored = await storage.getItem(STORAGE_KEY);
|
|
306
|
-
if (stored) {
|
|
307
|
-
const events: TelemetryEvent[] = JSON.parse(stored);
|
|
308
|
-
this.queue = [...events, ...this.queue];
|
|
309
|
-
await storage.removeItem(STORAGE_KEY);
|
|
310
|
-
logger.info(LOG_TAG, `Restored ${events.length} events from previous session`);
|
|
311
|
-
}
|
|
312
|
-
} catch {
|
|
313
|
-
// Silently fail — telemetry is non-critical
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// ─── Helpers ────────────────────────────────────────────────
|
|
318
|
-
|
|
319
|
-
/** Check if telemetry is configured */
|
|
320
|
-
private isEnabled(): boolean {
|
|
321
|
-
return !!(this.config.analyticsKey || this.config.analyticsProxyUrl);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TouchAutoCapture — Extracts a human-readable label from a React Native
|
|
3
|
-
* touch event target by walking up the native view hierarchy.
|
|
4
|
-
*
|
|
5
|
-
* Used by AIAgent to auto-track every tap in the app without
|
|
6
|
-
* any developer code changes (zero-config analytics).
|
|
7
|
-
*
|
|
8
|
-
* Strategy:
|
|
9
|
-
* 1. Read the touched element's accessibilityLabel (best signal).
|
|
10
|
-
* 2. If none, use React Native's internal _children to find nested text.
|
|
11
|
-
* 3. Fallback to the component's testID.
|
|
12
|
-
* 4. Last resort: "Unknown Element".
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// React Native imports not needed — we use Fiber internals directly
|
|
16
|
-
import type { TelemetryService } from './TelemetryService';
|
|
17
|
-
|
|
18
|
-
const recentTaps: { label: string; ts: number }[] = [];
|
|
19
|
-
const RAGE_WINDOW_MS = 2000;
|
|
20
|
-
const RAGE_THRESHOLD = 3;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Checks if the user is repeatedly tapping the same element in frustration.
|
|
24
|
-
* If rage click detected, emits 'rage_click' event to telemetry.
|
|
25
|
-
*/
|
|
26
|
-
export function checkRageClick(label: string, telemetry: TelemetryService): void {
|
|
27
|
-
const now = Date.now();
|
|
28
|
-
recentTaps.push({ label, ts: now });
|
|
29
|
-
|
|
30
|
-
// Keep buffer unbounded size of 5
|
|
31
|
-
if (recentTaps.length > 5) recentTaps.shift();
|
|
32
|
-
|
|
33
|
-
const recent = recentTaps.filter(t => t.label === label && now - t.ts < RAGE_WINDOW_MS);
|
|
34
|
-
if (recent.length >= RAGE_THRESHOLD) {
|
|
35
|
-
telemetry.track('rage_click', {
|
|
36
|
-
label,
|
|
37
|
-
count: recent.length,
|
|
38
|
-
screen: telemetry.screen
|
|
39
|
-
});
|
|
40
|
-
recentTaps.length = 0; // reset buffer after emitting to avoid spam
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Extract a label from a GestureResponderEvent's native target.
|
|
46
|
-
*
|
|
47
|
-
* @param nativeEvent - The nativeEvent from onStartShouldSetResponderCapture
|
|
48
|
-
* @param rootRef - The root View ref (to resolve relative positions)
|
|
49
|
-
* @returns A descriptive label string for the tapped element
|
|
50
|
-
*/
|
|
51
|
-
export function extractTouchLabel(nativeEvent: any): string {
|
|
52
|
-
// Try accessible properties first (most reliable)
|
|
53
|
-
const target = nativeEvent?.target;
|
|
54
|
-
|
|
55
|
-
if (!target) return 'Unknown Element';
|
|
56
|
-
|
|
57
|
-
// React Native internal: _internalFiberInstanceHandleDEV or _nativeTag
|
|
58
|
-
// We can walk the Fiber tree from the target to find text
|
|
59
|
-
try {
|
|
60
|
-
// Strategy 1: Walk up the Fiber tree from the touched element
|
|
61
|
-
let fiber = getFiberFromNativeTag(target);
|
|
62
|
-
if (fiber) {
|
|
63
|
-
// Walk up looking for text content or accessibility labels
|
|
64
|
-
let current: any = fiber;
|
|
65
|
-
let depth = 0;
|
|
66
|
-
const MAX_DEPTH = 10;
|
|
67
|
-
|
|
68
|
-
while (current && depth < MAX_DEPTH) {
|
|
69
|
-
// Check for accessibilityLabel
|
|
70
|
-
if (current.memoizedProps?.accessibilityLabel) {
|
|
71
|
-
return current.memoizedProps.accessibilityLabel;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Check for testID
|
|
75
|
-
if (current.memoizedProps?.testID) {
|
|
76
|
-
return current.memoizedProps.testID;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Check for title (Button component)
|
|
80
|
-
if (current.memoizedProps?.title) {
|
|
81
|
-
return current.memoizedProps.title;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Check for placeholder (TextInput)
|
|
85
|
-
if (current.memoizedProps?.placeholder) {
|
|
86
|
-
return `Input: ${current.memoizedProps.placeholder}`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Check if this is a Text node with children string
|
|
90
|
-
if (
|
|
91
|
-
typeof current.memoizedProps?.children === 'string' &&
|
|
92
|
-
current.memoizedProps.children.trim()
|
|
93
|
-
) {
|
|
94
|
-
return current.memoizedProps.children.trim();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Check for nested text in children array
|
|
98
|
-
if (Array.isArray(current.memoizedProps?.children)) {
|
|
99
|
-
const textChild = findTextInChildren(current.memoizedProps.children);
|
|
100
|
-
if (textChild) return textChild;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
current = current.return;
|
|
104
|
-
depth++;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// Fiber access failed — fall back gracefully
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return 'Unknown Element';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Find the first string text in a React children tree (recursive, max 3 levels).
|
|
116
|
-
*/
|
|
117
|
-
function findTextInChildren(children: any[], depth = 0): string | null {
|
|
118
|
-
if (depth > 3) return null;
|
|
119
|
-
|
|
120
|
-
for (const child of children) {
|
|
121
|
-
if (typeof child === 'string' && child.trim()) {
|
|
122
|
-
return child.trim();
|
|
123
|
-
}
|
|
124
|
-
if (typeof child === 'number') {
|
|
125
|
-
return String(child);
|
|
126
|
-
}
|
|
127
|
-
// React element with props.children
|
|
128
|
-
if (child?.props?.children) {
|
|
129
|
-
if (typeof child.props.children === 'string' && child.props.children.trim()) {
|
|
130
|
-
return child.props.children.trim();
|
|
131
|
-
}
|
|
132
|
-
if (Array.isArray(child.props.children)) {
|
|
133
|
-
const found = findTextInChildren(child.props.children, depth + 1);
|
|
134
|
-
if (found) return found;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Attempt to get the Fiber node from a native tag (React Native internal).
|
|
144
|
-
* This uses the same technique as React DevTools and testing libraries.
|
|
145
|
-
*/
|
|
146
|
-
function getFiberFromNativeTag(nativeTag: number): any {
|
|
147
|
-
try {
|
|
148
|
-
// React Native stores a reference from native tag → Fiber
|
|
149
|
-
// via the __internalInstanceHandle on the native node
|
|
150
|
-
const instance = (globalThis as any).__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
151
|
-
if (instance?.renderers) {
|
|
152
|
-
for (const [, renderer] of instance.renderers) {
|
|
153
|
-
if (renderer?.findFiberByHostInstance) {
|
|
154
|
-
// Try to find via the devtools hook
|
|
155
|
-
const fiber = renderer.findFiberByHostInstance(nativeTag);
|
|
156
|
-
if (fiber) return fiber;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
} catch {
|
|
161
|
-
// DevTools hook not available — expected in production
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistent device ID — a UUID generated on first launch and stored in AsyncStorage.
|
|
3
|
-
* Unique per app install, survives across sessions.
|
|
4
|
-
*
|
|
5
|
-
* AsyncStorage is an optional peer dependency — if not installed, the ID
|
|
6
|
-
* persists only in memory for the current session.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const STORAGE_KEY = '@mobileai:device_id';
|
|
10
|
-
|
|
11
|
-
let _cachedId: string | null = null;
|
|
12
|
-
let _storageLoaded = false;
|
|
13
|
-
let _storage: any = null;
|
|
14
|
-
|
|
15
|
-
function loadStorage(): any {
|
|
16
|
-
if (_storageLoaded) return _storage;
|
|
17
|
-
_storageLoaded = true;
|
|
18
|
-
try {
|
|
19
|
-
// Suppress the RN red box that AsyncStorage triggers when its native module
|
|
20
|
-
// isn't linked ("NativeModule: AsyncStorage is null").
|
|
21
|
-
const origError = console.error;
|
|
22
|
-
console.error = (...args: unknown[]) => {
|
|
23
|
-
const msg = args[0];
|
|
24
|
-
if (typeof msg === 'string' && msg.includes('AsyncStorage')) return;
|
|
25
|
-
origError.apply(console, args);
|
|
26
|
-
};
|
|
27
|
-
try {
|
|
28
|
-
const mod = require('@react-native-async-storage/async-storage');
|
|
29
|
-
const candidate = mod.default ?? mod;
|
|
30
|
-
if (candidate && typeof candidate.getItem === 'function') {
|
|
31
|
-
_storage = candidate;
|
|
32
|
-
}
|
|
33
|
-
} finally {
|
|
34
|
-
console.error = origError;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
// Not installed — device ID won't persist across restarts
|
|
38
|
-
}
|
|
39
|
-
return _storage;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function generateUUID(): string {
|
|
43
|
-
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
44
|
-
return crypto.randomUUID();
|
|
45
|
-
}
|
|
46
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
47
|
-
const r = (Math.random() * 16) | 0;
|
|
48
|
-
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
49
|
-
return v.toString(16);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Returns the persistent device ID synchronously (from cache).
|
|
55
|
-
* Returns null if not yet initialized.
|
|
56
|
-
*/
|
|
57
|
-
export function getDeviceId(): string | null {
|
|
58
|
-
return _cachedId;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Initializes or retrieves the persistent device ID.
|
|
63
|
-
* Call once on app startup. Subsequent getDeviceId() calls are synchronous.
|
|
64
|
-
*/
|
|
65
|
-
export async function initDeviceId(): Promise<string> {
|
|
66
|
-
if (_cachedId) return _cachedId;
|
|
67
|
-
|
|
68
|
-
const storage = loadStorage();
|
|
69
|
-
if (storage) {
|
|
70
|
-
try {
|
|
71
|
-
const stored: string | null = await storage.getItem(STORAGE_KEY);
|
|
72
|
-
if (stored) {
|
|
73
|
-
_cachedId = stored;
|
|
74
|
-
return stored;
|
|
75
|
-
}
|
|
76
|
-
} catch {
|
|
77
|
-
// Storage read failed — continue with new ID
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const newId = generateUUID();
|
|
82
|
-
_cachedId = newId;
|
|
83
|
-
|
|
84
|
-
if (storage) {
|
|
85
|
-
try {
|
|
86
|
-
await storage.setItem(STORAGE_KEY, newId);
|
|
87
|
-
} catch {
|
|
88
|
-
// Storage write failed — ID works for this session only
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return newId;
|
|
93
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Platform } from 'react-native';
|
|
2
|
-
|
|
3
|
-
export interface DeviceMetadata {
|
|
4
|
-
platform: string;
|
|
5
|
-
osVersion: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function getDeviceMetadata(): DeviceMetadata {
|
|
9
|
-
return {
|
|
10
|
-
platform: Platform.OS === 'ios' ? 'iOS' : Platform.OS === 'android' ? 'Android' : Platform.OS,
|
|
11
|
-
osVersion: String(Platform.Version),
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry module barrel export.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { TelemetryService } from './TelemetryService';
|
|
6
|
-
export { MobileAI, bindTelemetryService } from './MobileAI';
|
|
7
|
-
export type {
|
|
8
|
-
TelemetryEvent,
|
|
9
|
-
TelemetryBatch,
|
|
10
|
-
TelemetryConfig,
|
|
11
|
-
AutoEventType,
|
|
12
|
-
EventType,
|
|
13
|
-
} from './types';
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry types for the MobileAI analytics module.
|
|
3
|
-
*
|
|
4
|
-
* Events are split into two categories:
|
|
5
|
-
* 1. Auto-captured: SDK captures these without consumer code
|
|
6
|
-
* 2. Consumer-tracked: via MobileAI.track() API
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// ─── Event Types ──────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
/** Auto-captured event types */
|
|
12
|
-
export type AutoEventType =
|
|
13
|
-
| 'screen_view'
|
|
14
|
-
| 'user_action'
|
|
15
|
-
| 'scroll_depth'
|
|
16
|
-
| 'idle_detected'
|
|
17
|
-
| 'session_start'
|
|
18
|
-
| 'session_end'
|
|
19
|
-
| 'agent_request'
|
|
20
|
-
| 'agent_step'
|
|
21
|
-
| 'agent_complete'
|
|
22
|
-
| 'escalation'
|
|
23
|
-
| 'knowledge_query'
|
|
24
|
-
| 'knowledge_miss'
|
|
25
|
-
| 'csat_response';
|
|
26
|
-
|
|
27
|
-
/** All event types (auto + custom) */
|
|
28
|
-
export type EventType = AutoEventType | string;
|
|
29
|
-
|
|
30
|
-
// ─── Event Payload ────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
export interface TelemetryEvent {
|
|
33
|
-
/** Event type identifier */
|
|
34
|
-
type: EventType;
|
|
35
|
-
/** Event-specific data */
|
|
36
|
-
data: Record<string, unknown>;
|
|
37
|
-
/** ISO 8601 timestamp (auto-set by SDK) */
|
|
38
|
-
timestamp: string;
|
|
39
|
-
/** Current screen name (auto-attached) */
|
|
40
|
-
screen: string;
|
|
41
|
-
/** Session ID (auto-generated per app lifecycle) */
|
|
42
|
-
sessionId: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ─── Batch Payload (sent to cloud) ────────────────────────────
|
|
46
|
-
|
|
47
|
-
export interface TelemetryBatch {
|
|
48
|
-
/** Publishable analytics key */
|
|
49
|
-
analyticsKey: string;
|
|
50
|
-
/** App identifier (bundle ID / package name) */
|
|
51
|
-
appId: string;
|
|
52
|
-
/** Hashed user/device identifier */
|
|
53
|
-
deviceId: string;
|
|
54
|
-
/** SDK version */
|
|
55
|
-
sdkVersion: string;
|
|
56
|
-
/** Batch of events */
|
|
57
|
-
events: TelemetryEvent[];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ─── Configuration ────────────────────────────────────────────
|
|
61
|
-
|
|
62
|
-
export interface TelemetryConfig {
|
|
63
|
-
/** Publishable analytics key (mobileai_pub_xxx) */
|
|
64
|
-
analyticsKey?: string;
|
|
65
|
-
/** Proxy URL for enterprise customers (replaces direct cloud API) */
|
|
66
|
-
analyticsProxyUrl?: string;
|
|
67
|
-
/** Custom headers for proxy requests */
|
|
68
|
-
analyticsProxyHeaders?: Record<string, string>;
|
|
69
|
-
/** Flush interval in ms (default: 30000) */
|
|
70
|
-
flushIntervalMs?: number;
|
|
71
|
-
/** Max events before auto-flush (default: 50) */
|
|
72
|
-
maxBatchSize?: number;
|
|
73
|
-
/** Enable debug logging for telemetry (default: false) */
|
|
74
|
-
debug?: boolean;
|
|
75
|
-
}
|