@repliqo/sdk-react-native 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INTEGRATION_GUIDE.md +1384 -1312
- package/android/src/main/java/com/repliqo/screencapture/MultiWindowCapture.java +242 -230
- package/android/src/main/java/com/repliqo/screencapture/ScreenCaptureModule.java +94 -170
- package/dist/components/RepliqoFlatList.d.ts +5 -0
- package/dist/components/RepliqoFlatList.js +39 -0
- package/dist/components/RepliqoScrollView.d.ts +3 -0
- package/dist/components/RepliqoScrollView.js +16 -265
- package/dist/components/useRepliqoScrollTracking.d.ts +33 -0
- package/dist/components/useRepliqoScrollTracking.js +304 -0
- package/dist/core/client.d.ts +52 -5
- package/dist/core/client.js +310 -48
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +5 -1
- package/dist/core/storage.d.ts +29 -0
- package/dist/core/storage.js +33 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/snapshot/NativeScreenCapture.d.ts +6 -44
- package/dist/snapshot/NativeScreenCapture.js +6 -64
- package/dist/snapshot/capture.d.ts +7 -0
- package/dist/snapshot/capture.js +17 -5
- package/dist/trackers/error.tracker.d.ts +25 -0
- package/dist/trackers/error.tracker.js +114 -37
- package/dist/trackers/navigation.tracker.js +11 -0
- package/dist/transport/api.client.d.ts +34 -1
- package/dist/transport/api.client.js +102 -19
- package/dist/transport/batch-queue.d.ts +53 -1
- package/dist/transport/batch-queue.js +126 -19
- package/dist/types/events.d.ts +12 -0
- package/package.json +68 -64
- package/src/components/RepliqoFlatList.tsx +64 -0
- package/src/components/RepliqoScrollView.tsx +53 -302
- package/src/components/useRepliqoScrollTracking.ts +366 -0
- package/src/core/client.ts +953 -672
- package/src/core/config.ts +38 -30
- package/src/core/storage.ts +51 -0
- package/src/index.ts +54 -52
- package/src/snapshot/NativeScreenCapture.ts +62 -157
- package/src/snapshot/capture.ts +154 -142
- package/src/trackers/error.tracker.ts +211 -136
- package/src/trackers/navigation.tracker.ts +107 -98
- package/src/transport/api.client.ts +430 -327
- package/src/transport/batch-queue.ts +212 -95
- package/src/types/events.ts +72 -60
- package/android/src/main/java/com/repliqo/screencapture/FullContentCapture.java +0 -273
- package/android/src/main/java/com/repliqo/screencapture/PixelCopyScan.java +0 -279
- package/android/src/main/java/com/repliqo/screencapture/ScrollScanCapture.java +0 -248
- package/src/snapshot/ScreenCaptureManager.ts +0 -156
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useRepliqoScrollTracking = useRepliqoScrollTracking;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const react_native_1 = require("react-native");
|
|
6
|
+
const client_1 = require("../core/client");
|
|
7
|
+
/** Minimum scroll delta (px) to trigger a new tile capture. */
|
|
8
|
+
const MIN_DELTA_PX = 20;
|
|
9
|
+
/** Debounce: wait this long after scroll stops before capturing. */
|
|
10
|
+
const DEBOUNCE_MS = 250;
|
|
11
|
+
/** Throttle: minimum time between tile captures. */
|
|
12
|
+
const THROTTLE_MS = 400;
|
|
13
|
+
/**
|
|
14
|
+
* During continuous scroll, force a capture every this many ms.
|
|
15
|
+
* Ensures tiles are captured even during fast, uninterrupted scrolls
|
|
16
|
+
* where the user never pauses long enough for the debounce to fire.
|
|
17
|
+
*/
|
|
18
|
+
const SCROLL_INTERVAL_MS = 1200;
|
|
19
|
+
/**
|
|
20
|
+
* During scroll, throttle window-bounds re-measurement to at most once per
|
|
21
|
+
* this many ms. Bounds rarely change while scrolling, but we still want to
|
|
22
|
+
* catch orientation changes / keyboard / overlay animations.
|
|
23
|
+
*/
|
|
24
|
+
const REMEASURE_THROTTLE_MS = 500;
|
|
25
|
+
/**
|
|
26
|
+
* The continuous-scroll interval self-stops when no scroll event has been
|
|
27
|
+
* seen for this long. Programmatic scrolls (scrollTo / Animated) fire
|
|
28
|
+
* onScroll but never onScrollEndDrag/onMomentumScrollEnd — without this,
|
|
29
|
+
* the interval would keep running until unmount.
|
|
30
|
+
*/
|
|
31
|
+
const INTERVAL_IDLE_STOP_MS = SCROLL_INTERVAL_MS * 2;
|
|
32
|
+
let scrollViewIdCounter = 0;
|
|
33
|
+
const nextScrollViewId = () => `repliqo-scroll-${++scrollViewIdCounter}`;
|
|
34
|
+
/**
|
|
35
|
+
* Shared scroll-analytics behavior behind RepliqoScrollView and
|
|
36
|
+
* RepliqoFlatList:
|
|
37
|
+
*
|
|
38
|
+
* 1. Reports scroll offset for accurate heatmap touch coords
|
|
39
|
+
* 2. Captures viewport tiles on scroll stops AND during continuous
|
|
40
|
+
* scroll for collaborative screen building
|
|
41
|
+
* 3. Registers window-relative bounds with the SDK so touches are
|
|
42
|
+
* auto-classified as content (inside) vs fixed UI (outside)
|
|
43
|
+
*
|
|
44
|
+
* @param forwardedRef The consumer's ref (function or object).
|
|
45
|
+
* @param userHandlers The consumer's own scroll/layout handlers — always
|
|
46
|
+
* called after the SDK's.
|
|
47
|
+
*/
|
|
48
|
+
function useRepliqoScrollTracking(forwardedRef, userHandlers) {
|
|
49
|
+
const debounceTimer = (0, react_1.useRef)(null);
|
|
50
|
+
const scrollIntervalTimer = (0, react_1.useRef)(null);
|
|
51
|
+
const initialLayoutTimer = (0, react_1.useRef)(null);
|
|
52
|
+
const lastCaptureTime = (0, react_1.useRef)(0);
|
|
53
|
+
const lastCaptureY = (0, react_1.useRef)(-999);
|
|
54
|
+
const lastMeasureTime = (0, react_1.useRef)(0);
|
|
55
|
+
const lastScrollEventAt = (0, react_1.useRef)(0);
|
|
56
|
+
const initialCaptured = (0, react_1.useRef)(false);
|
|
57
|
+
const realContentHeight = (0, react_1.useRef)(0);
|
|
58
|
+
const scrollViewId = (0, react_1.useRef)(nextScrollViewId());
|
|
59
|
+
const innerRef = (0, react_1.useRef)(null);
|
|
60
|
+
const isMounted = (0, react_1.useRef)(true);
|
|
61
|
+
// Last measured window-relative top Y — passed to captureScrollTile so
|
|
62
|
+
// the backend can crop each tile to just the scroll viewport area.
|
|
63
|
+
const lastViewportTop = (0, react_1.useRef)(null);
|
|
64
|
+
const scrollState = (0, react_1.useRef)(null);
|
|
65
|
+
// Keep the latest user handlers in a ref so our stable callbacks always
|
|
66
|
+
// call the current ones.
|
|
67
|
+
const handlersRef = (0, react_1.useRef)(userHandlers);
|
|
68
|
+
handlersRef.current = userHandlers;
|
|
69
|
+
// Forward the inner ref to the consumer's ref (if provided).
|
|
70
|
+
// IMPORTANT: do NOT clear innerRef on cleanup — RN sometimes calls the
|
|
71
|
+
// ref callback with null mid-update, and clearing would break async
|
|
72
|
+
// measurement callbacks that fire after the ref reattaches.
|
|
73
|
+
const setRef = (0, react_1.useCallback)((node) => {
|
|
74
|
+
if (node !== null) {
|
|
75
|
+
innerRef.current = node;
|
|
76
|
+
}
|
|
77
|
+
if (typeof forwardedRef === 'function') {
|
|
78
|
+
forwardedRef(node);
|
|
79
|
+
}
|
|
80
|
+
else if (forwardedRef) {
|
|
81
|
+
forwardedRef.current = node;
|
|
82
|
+
}
|
|
83
|
+
}, [forwardedRef]);
|
|
84
|
+
/**
|
|
85
|
+
* Resolve the node that actually supports measureInWindow. FlatList (and
|
|
86
|
+
* other VirtualizedList wrappers) don't expose it directly — their inner
|
|
87
|
+
* ScrollView does, reachable via getNativeScrollRef().
|
|
88
|
+
*/
|
|
89
|
+
const resolveMeasurableNode = () => {
|
|
90
|
+
const node = innerRef.current;
|
|
91
|
+
if (!node)
|
|
92
|
+
return null;
|
|
93
|
+
if (typeof node.measureInWindow === 'function')
|
|
94
|
+
return node;
|
|
95
|
+
try {
|
|
96
|
+
const inner = typeof node.getNativeScrollRef === 'function'
|
|
97
|
+
? node.getNativeScrollRef()
|
|
98
|
+
: typeof node.getScrollableNode === 'function'
|
|
99
|
+
? node.getScrollableNode()
|
|
100
|
+
: null;
|
|
101
|
+
if (inner && typeof inner.measureInWindow === 'function')
|
|
102
|
+
return inner;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* ignore */
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Measure window-relative bounds and register with the SDK.
|
|
111
|
+
* Idempotent + safe to call after unmount (guards via isMounted).
|
|
112
|
+
*/
|
|
113
|
+
const measureAndRegister = (0, react_1.useCallback)(() => {
|
|
114
|
+
if (!isMounted.current)
|
|
115
|
+
return;
|
|
116
|
+
const node = resolveMeasurableNode();
|
|
117
|
+
if (!node)
|
|
118
|
+
return;
|
|
119
|
+
node.measureInWindow((x, y, width, height) => {
|
|
120
|
+
if (!isMounted.current)
|
|
121
|
+
return;
|
|
122
|
+
// RN sometimes returns 0/0 dims before the view is positioned —
|
|
123
|
+
// ignore those, the next onLayout/onScroll will re-measure.
|
|
124
|
+
if (width <= 0 || height <= 0)
|
|
125
|
+
return;
|
|
126
|
+
lastViewportTop.current = y;
|
|
127
|
+
try {
|
|
128
|
+
client_1.AppAnalytics.getInstance().registerScrollView(scrollViewId.current, {
|
|
129
|
+
x, y, width, height,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch { }
|
|
133
|
+
});
|
|
134
|
+
}, []);
|
|
135
|
+
// Cleanup all timers + unregister + listeners on unmount
|
|
136
|
+
(0, react_1.useEffect)(() => {
|
|
137
|
+
const id = scrollViewId.current;
|
|
138
|
+
isMounted.current = true;
|
|
139
|
+
// Re-measure when keyboard appears/disappears (causes layout shift)
|
|
140
|
+
const showSub = react_native_1.Keyboard.addListener('keyboardDidShow', measureAndRegister);
|
|
141
|
+
const hideSub = react_native_1.Keyboard.addListener('keyboardDidHide', measureAndRegister);
|
|
142
|
+
return () => {
|
|
143
|
+
isMounted.current = false;
|
|
144
|
+
if (debounceTimer.current)
|
|
145
|
+
clearTimeout(debounceTimer.current);
|
|
146
|
+
if (scrollIntervalTimer.current)
|
|
147
|
+
clearInterval(scrollIntervalTimer.current);
|
|
148
|
+
if (initialLayoutTimer.current)
|
|
149
|
+
clearTimeout(initialLayoutTimer.current);
|
|
150
|
+
showSub.remove();
|
|
151
|
+
hideSub.remove();
|
|
152
|
+
try {
|
|
153
|
+
client_1.AppAnalytics.getInstance().unregisterScrollView(id);
|
|
154
|
+
}
|
|
155
|
+
catch { }
|
|
156
|
+
};
|
|
157
|
+
}, [measureAndRegister]);
|
|
158
|
+
/**
|
|
159
|
+
* Core tile capture logic. Reads from refs (stable across renders).
|
|
160
|
+
* Checks throttle + delta before capturing.
|
|
161
|
+
*
|
|
162
|
+
* @param force Skip throttle check (used for interval captures)
|
|
163
|
+
*/
|
|
164
|
+
const doCapture = (force = false) => {
|
|
165
|
+
if (!isMounted.current)
|
|
166
|
+
return;
|
|
167
|
+
const state = scrollState.current;
|
|
168
|
+
if (!state || state.viewportHeight <= 0)
|
|
169
|
+
return;
|
|
170
|
+
const now = Date.now();
|
|
171
|
+
if (!force && now - lastCaptureTime.current < THROTTLE_MS)
|
|
172
|
+
return;
|
|
173
|
+
// Always check delta — no point re-capturing the same position
|
|
174
|
+
if (Math.abs(state.offsetY - lastCaptureY.current) < MIN_DELTA_PX &&
|
|
175
|
+
initialCaptured.current)
|
|
176
|
+
return;
|
|
177
|
+
lastCaptureTime.current = now;
|
|
178
|
+
lastCaptureY.current = state.offsetY;
|
|
179
|
+
initialCaptured.current = true;
|
|
180
|
+
try {
|
|
181
|
+
const windowHeight = react_native_1.Dimensions.get('window').height;
|
|
182
|
+
client_1.AppAnalytics.getInstance().captureScrollTile(state.offsetY, state.viewportHeight, state.contentHeight, lastViewportTop.current ?? undefined, windowHeight);
|
|
183
|
+
}
|
|
184
|
+
catch { }
|
|
185
|
+
};
|
|
186
|
+
/** Stop the continuous-scroll interval timer. */
|
|
187
|
+
const stopScrollInterval = () => {
|
|
188
|
+
if (scrollIntervalTimer.current !== null) {
|
|
189
|
+
clearInterval(scrollIntervalTimer.current);
|
|
190
|
+
scrollIntervalTimer.current = null;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Start the interval timer for continuous scroll captures. Self-stops
|
|
195
|
+
* when scroll events stop arriving (programmatic scrolls never fire the
|
|
196
|
+
* drag/momentum end events that would stop it otherwise).
|
|
197
|
+
*/
|
|
198
|
+
const startScrollInterval = () => {
|
|
199
|
+
if (scrollIntervalTimer.current !== null)
|
|
200
|
+
return;
|
|
201
|
+
scrollIntervalTimer.current = setInterval(() => {
|
|
202
|
+
if (Date.now() - lastScrollEventAt.current > INTERVAL_IDLE_STOP_MS) {
|
|
203
|
+
stopScrollInterval();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
doCapture(true); // force=true skips throttle
|
|
207
|
+
}, SCROLL_INTERVAL_MS);
|
|
208
|
+
};
|
|
209
|
+
const onScroll = (0, react_1.useCallback)((event) => {
|
|
210
|
+
const { contentOffset, layoutMeasurement, contentSize } = event.nativeEvent;
|
|
211
|
+
lastScrollEventAt.current = Date.now();
|
|
212
|
+
// Update SDK with current scroll offset (both legacy + new registry)
|
|
213
|
+
try {
|
|
214
|
+
const sdk = client_1.AppAnalytics.getInstance();
|
|
215
|
+
sdk.setScrollOffset(contentOffset.y);
|
|
216
|
+
sdk.updateScrollViewOffset(scrollViewId.current, contentOffset.y);
|
|
217
|
+
}
|
|
218
|
+
catch { }
|
|
219
|
+
// Re-measure bounds occasionally during scroll — catches layout
|
|
220
|
+
// shifts from animations, keyboard, orientation changes, etc.
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
if (now - lastMeasureTime.current > REMEASURE_THROTTLE_MS) {
|
|
223
|
+
lastMeasureTime.current = now;
|
|
224
|
+
measureAndRegister();
|
|
225
|
+
}
|
|
226
|
+
// Update scroll state — use realContentHeight if available
|
|
227
|
+
const bestContentHeight = realContentHeight.current > 0
|
|
228
|
+
? realContentHeight.current
|
|
229
|
+
: contentSize.height;
|
|
230
|
+
scrollState.current = {
|
|
231
|
+
offsetY: contentOffset.y,
|
|
232
|
+
viewportHeight: layoutMeasurement.height,
|
|
233
|
+
contentHeight: bestContentHeight,
|
|
234
|
+
};
|
|
235
|
+
// Debounce: capture after scroll stops
|
|
236
|
+
if (debounceTimer.current)
|
|
237
|
+
clearTimeout(debounceTimer.current);
|
|
238
|
+
debounceTimer.current = setTimeout(() => doCapture(), DEBOUNCE_MS);
|
|
239
|
+
// Start interval for continuous scroll captures
|
|
240
|
+
startScrollInterval();
|
|
241
|
+
// Capture initial tile (Y~0) on first scroll event with real dims
|
|
242
|
+
if (!initialCaptured.current && contentOffset.y < 10) {
|
|
243
|
+
if (initialLayoutTimer.current)
|
|
244
|
+
clearTimeout(initialLayoutTimer.current);
|
|
245
|
+
initialLayoutTimer.current = setTimeout(() => doCapture(), 200);
|
|
246
|
+
}
|
|
247
|
+
handlersRef.current.onScroll?.(event);
|
|
248
|
+
}, [measureAndRegister]);
|
|
249
|
+
const onScrollEndDrag = (0, react_1.useCallback)((event) => {
|
|
250
|
+
// User lifted finger — capture immediately
|
|
251
|
+
stopScrollInterval();
|
|
252
|
+
doCapture(true);
|
|
253
|
+
handlersRef.current.onScrollEndDrag?.(event);
|
|
254
|
+
}, []);
|
|
255
|
+
const onMomentumScrollEnd = (0, react_1.useCallback)((event) => {
|
|
256
|
+
if (debounceTimer.current) {
|
|
257
|
+
clearTimeout(debounceTimer.current);
|
|
258
|
+
debounceTimer.current = null;
|
|
259
|
+
}
|
|
260
|
+
stopScrollInterval();
|
|
261
|
+
doCapture(true);
|
|
262
|
+
handlersRef.current.onMomentumScrollEnd?.(event);
|
|
263
|
+
}, []);
|
|
264
|
+
const onLayout = (0, react_1.useCallback)((event) => {
|
|
265
|
+
const { height } = event.nativeEvent.layout;
|
|
266
|
+
if (!initialCaptured.current && height > 0) {
|
|
267
|
+
scrollState.current = {
|
|
268
|
+
offsetY: 0,
|
|
269
|
+
viewportHeight: height,
|
|
270
|
+
contentHeight: realContentHeight.current || height,
|
|
271
|
+
};
|
|
272
|
+
// Clear any prior pending initial-capture timer before scheduling
|
|
273
|
+
if (initialLayoutTimer.current)
|
|
274
|
+
clearTimeout(initialLayoutTimer.current);
|
|
275
|
+
initialLayoutTimer.current = setTimeout(() => doCapture(), 1000);
|
|
276
|
+
}
|
|
277
|
+
// Register window-relative bounds immediately (no setTimeout).
|
|
278
|
+
// measureInWindow itself is async; if it returns 0/0 dims, the
|
|
279
|
+
// next onLayout / onScroll will retry — no race window.
|
|
280
|
+
measureAndRegister();
|
|
281
|
+
handlersRef.current.onLayout?.(event);
|
|
282
|
+
}, [measureAndRegister]);
|
|
283
|
+
/**
|
|
284
|
+
* Track the real content height from onContentSizeChange.
|
|
285
|
+
* This is more reliable than the first scroll event and ensures
|
|
286
|
+
* the initial tile at Y=0 has correct contentHeight metadata.
|
|
287
|
+
*/
|
|
288
|
+
const onContentSizeChange = (0, react_1.useCallback)((w, h) => {
|
|
289
|
+
realContentHeight.current = h;
|
|
290
|
+
// Update scroll state if it exists
|
|
291
|
+
if (scrollState.current) {
|
|
292
|
+
scrollState.current.contentHeight = h;
|
|
293
|
+
}
|
|
294
|
+
handlersRef.current.onContentSizeChange?.(w, h);
|
|
295
|
+
}, []);
|
|
296
|
+
return {
|
|
297
|
+
setRef,
|
|
298
|
+
onScroll,
|
|
299
|
+
onScrollEndDrag,
|
|
300
|
+
onMomentumScrollEnd,
|
|
301
|
+
onLayout,
|
|
302
|
+
onContentSizeChange,
|
|
303
|
+
};
|
|
304
|
+
}
|
package/dist/core/client.d.ts
CHANGED
|
@@ -14,6 +14,18 @@ export declare class AppAnalytics {
|
|
|
14
14
|
private scrollOffsetY;
|
|
15
15
|
private logger;
|
|
16
16
|
private appStateSubscription;
|
|
17
|
+
/**
|
|
18
|
+
* User identity set via identify(). Kept for the process lifetime and
|
|
19
|
+
* automatically re-attached to every new session, so the host app only
|
|
20
|
+
* needs to call identify() once (e.g. after login).
|
|
21
|
+
*/
|
|
22
|
+
private identity;
|
|
23
|
+
/**
|
|
24
|
+
* Offline persistence backend (AsyncStorage-compatible). Null when the
|
|
25
|
+
* host app neither passed one nor has AsyncStorage installed — the SDK
|
|
26
|
+
* then behaves exactly as before (in-memory buffering only).
|
|
27
|
+
*/
|
|
28
|
+
private storage;
|
|
17
29
|
/**
|
|
18
30
|
* Registry of active ScrollViews on the current screen.
|
|
19
31
|
* Each RepliqoScrollView registers its window-relative bounds and current
|
|
@@ -49,6 +61,21 @@ export declare class AppAnalytics {
|
|
|
49
61
|
trackTouch(x: number, y: number, screenName?: string, extra?: Record<string, any>): void;
|
|
50
62
|
trackNavigation(fromScreen: string, toScreen: string): void;
|
|
51
63
|
trackCustomEvent(eventName: string, data?: Record<string, any>): void;
|
|
64
|
+
/**
|
|
65
|
+
* Identify the current user (call once after login). The identity is
|
|
66
|
+
* attached to the active session immediately and re-attached to every
|
|
67
|
+
* future session automatically until resetIdentity() is called.
|
|
68
|
+
*
|
|
69
|
+
* @param userId The host app's own user identifier.
|
|
70
|
+
* @param traits Optional free-form traits (plan, role, locale...).
|
|
71
|
+
* Avoid PII you don't want stored (emails in plain text).
|
|
72
|
+
*/
|
|
73
|
+
identify(userId: string, traits?: Record<string, unknown>): void;
|
|
74
|
+
/**
|
|
75
|
+
* Clear the stored identity (call on logout). Sessions started after
|
|
76
|
+
* this are anonymous again; already-identified sessions keep their user.
|
|
77
|
+
*/
|
|
78
|
+
resetIdentity(): void;
|
|
52
79
|
reportError(error: Error, metadata?: Record<string, any>): void;
|
|
53
80
|
/**
|
|
54
81
|
* Update the current scroll offset. Called by RepliqoScrollView
|
|
@@ -95,11 +122,6 @@ export declare class AppAnalytics {
|
|
|
95
122
|
* scale computation during backend cropping.
|
|
96
123
|
*/
|
|
97
124
|
captureScrollTile(scrollOffsetY: number, viewportHeight: number, contentHeight: number, viewportTop?: number, windowHeight?: number): void;
|
|
98
|
-
/**
|
|
99
|
-
* Programmatically scroll-scan the current ScrollView and upload all
|
|
100
|
-
* tiles to the backend. Invisible to the user (~300-500ms).
|
|
101
|
-
*/
|
|
102
|
-
private autoScanScreen;
|
|
103
125
|
onScreenEnter(screenName: string): void;
|
|
104
126
|
onScreenExit(screenName: string): void;
|
|
105
127
|
flush(): Promise<void>;
|
|
@@ -114,5 +136,30 @@ export declare class AppAnalytics {
|
|
|
114
136
|
startSnapshotCapture(): void;
|
|
115
137
|
stopSnapshotCapture(): void;
|
|
116
138
|
isInitialized(): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* Persist the un-flushed event buffer (called when backgrounding).
|
|
141
|
+
* Events carry their __sessionId stamp, so on restore they are still
|
|
142
|
+
* attributed to the session they belonged to.
|
|
143
|
+
*/
|
|
144
|
+
private persistPendingEvents;
|
|
145
|
+
/**
|
|
146
|
+
* Serialization chain for pending-crash read-modify-write operations.
|
|
147
|
+
* Two near-simultaneous crashes (e.g. an error cascade) would otherwise
|
|
148
|
+
* interleave getItem/setItem and lose one of the entries.
|
|
149
|
+
*/
|
|
150
|
+
private crashStoreLock;
|
|
151
|
+
private withCrashStoreLock;
|
|
152
|
+
/** Monotonic suffix so identical crashes get distinct keys. */
|
|
153
|
+
private crashSeq;
|
|
154
|
+
/** Append a crash to the persisted pending list; returns its key. */
|
|
155
|
+
private persistCrash;
|
|
156
|
+
/** Remove a crash from the persisted pending list (after send success). */
|
|
157
|
+
private removePendingCrash;
|
|
158
|
+
/**
|
|
159
|
+
* Restore data persisted by a previous run: re-enqueue events (still
|
|
160
|
+
* stamped with their original session) and re-send pending crashes.
|
|
161
|
+
* Called once from the constructor.
|
|
162
|
+
*/
|
|
163
|
+
private restorePersistedData;
|
|
117
164
|
private setupAppStateListener;
|
|
118
165
|
}
|