noibu-react-native 0.2.7 → 0.2.9

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.
Files changed (71) hide show
  1. package/android/build.gradle +1 -1
  2. package/dist/api/ClientConfig.d.ts +99 -0
  3. package/dist/api/ClientConfig.js +24 -23
  4. package/dist/api/ClientConfig.test.d.ts +1 -0
  5. package/dist/api/HelpCode.d.ts +16 -0
  6. package/dist/api/HelpCode.js +2 -2
  7. package/dist/api/InputManager.d.ts +39 -0
  8. package/dist/api/InputManager.js +1 -3
  9. package/dist/api/MetroplexSocket.d.ts +132 -0
  10. package/dist/api/MetroplexSocket.js +4 -8
  11. package/dist/api/MetroplexSocket.test.d.ts +1 -0
  12. package/dist/api/StoredMetrics.d.ts +63 -0
  13. package/dist/api/StoredPageVisit.d.ts +43 -0
  14. package/dist/api/StoredPageVisit.js +4 -6
  15. package/dist/const_matchers.d.ts +1 -0
  16. package/dist/constants.d.ts +48 -0
  17. package/dist/constants.js +3 -10
  18. package/dist/entry/index.d.ts +13 -0
  19. package/dist/entry/init.d.ts +8 -0
  20. package/dist/entry/init.js +4 -4
  21. package/dist/monitors/AppNavigationMonitor.d.ts +10 -0
  22. package/dist/monitors/AppNavigationMonitor.js +2 -4
  23. package/dist/monitors/AppNavigationMonitor.test.d.ts +1 -0
  24. package/dist/monitors/BaseMonitor.d.ts +13 -0
  25. package/dist/monitors/BaseMonitor.test.d.ts +1 -0
  26. package/dist/monitors/ClickMonitor.d.ts +28 -0
  27. package/dist/monitors/ClickMonitor.js +1 -3
  28. package/dist/monitors/ClickMonitor.test.d.ts +1 -0
  29. package/dist/monitors/ErrorMonitor.d.ts +39 -0
  30. package/dist/monitors/ErrorMonitor.js +1 -2
  31. package/dist/monitors/KeyboardInputMonitor.d.ts +18 -0
  32. package/dist/monitors/KeyboardInputMonitor.js +1 -3
  33. package/dist/monitors/PageMonitor.d.ts +20 -0
  34. package/dist/monitors/PageMonitor.js +1 -2
  35. package/dist/monitors/RequestMonitor.d.ts +74 -0
  36. package/dist/monitors/RequestMonitor.js +8 -10
  37. package/dist/monitors/http-tools/GqlErrorValidator.d.ts +35 -0
  38. package/dist/monitors/http-tools/GqlErrorValidator.js +4 -3
  39. package/dist/monitors/http-tools/HTTPDataBundler.d.ts +106 -0
  40. package/dist/monitors/http-tools/HTTPDataBundler.js +6 -5
  41. package/dist/monitors/integrations/ReactNativeNavigationIntegration.d.ts +17 -0
  42. package/dist/pageVisit/EventDebouncer.d.ts +23 -0
  43. package/dist/pageVisit/HttpEventManager.d.ts +14 -0
  44. package/dist/pageVisit/HttpEventManager.js +1 -3
  45. package/dist/pageVisit/PageVisitManager.d.ts +31 -0
  46. package/dist/pageVisit/PageVisitManager.js +1 -2
  47. package/dist/pageVisit/pageVisitEventError.d.ts +12 -0
  48. package/dist/pageVisit/pageVisitEventError.js +2 -6
  49. package/dist/react/ErrorBoundary.d.ts +67 -0
  50. package/dist/sessionRecorder/SessionRecorder.d.ts +50 -0
  51. package/dist/sessionRecorder/SessionRecorder.js +7 -8
  52. package/dist/sessionRecorder/nativeSessionRecorderSubscription.d.ts +77 -0
  53. package/dist/sessionRecorder/types.d.ts +91 -0
  54. package/dist/storage/RNStorageProvider.d.ts +19 -0
  55. package/dist/storage/Storage.d.ts +29 -0
  56. package/dist/storage/StorageProvider.d.ts +23 -0
  57. package/dist/types/NavigationIntegration.d.ts +6 -0
  58. package/dist/utils/date.d.ts +7 -0
  59. package/dist/utils/date.js +2 -2
  60. package/dist/utils/eventlistener.d.ts +8 -0
  61. package/dist/utils/eventlistener.js +2 -3
  62. package/dist/utils/function.d.ts +72 -0
  63. package/dist/utils/log.d.ts +4 -0
  64. package/dist/utils/log.js +1 -3
  65. package/dist/utils/object.d.ts +46 -0
  66. package/dist/utils/performance.d.ts +6 -0
  67. package/dist/utils/piiRedactor.d.ts +11 -0
  68. package/dist/utils/polyfills.d.ts +4 -0
  69. package/dist/utils/stacktrace-parser.d.ts +8 -0
  70. package/dist/utils/stacktrace-parser.test.d.ts +1 -0
  71. package/package.json +4 -2
@@ -0,0 +1,106 @@
1
+ import { Singleton } from '../BaseMonitor';
2
+ import { NoSeq } from '../../types/Metroplex';
3
+ import { RawHttpData } from 'noibu-metroplex-ts-bindings';
4
+ /** Bundles HTTP payloads and headers */
5
+ export declare class HTTPDataBundler extends Singleton {
6
+ contentTypeReadableRegex: RegExp;
7
+ hostname: string;
8
+ initialURLPartsReversed: string[];
9
+ httpDataCollectionEnabled: boolean;
10
+ httpDataAllowedRelativeRegex: RegExp | null;
11
+ httpDataAllowedAbsoluteRegex: RegExp | null;
12
+ /** Creates an instance of the ClickMonitor instance */
13
+ constructor();
14
+ /**
15
+ * Builds the HTTP payload allowed regexes for full and relative URLs
16
+ * @param allowedURLs Target list of allowed URLs
17
+ * @param absolute Use only absolute URLs if true, use only relative URL if false
18
+ * @returns a regex of allowed URLs
19
+ */
20
+ private static buildAllowedRegex;
21
+ /**
22
+ * Takes an iterator and returns a map of strings representing headers.
23
+ * param {object} headersIterable any iterable object
24
+ * returns a map of strings (as expected by metroplex) representing HTTP
25
+ * request or response headers
26
+ */
27
+ static headersMapFromIterable(headersIterable: Iterable<any[]>): Map<any, any>;
28
+ /**
29
+ * Takes a string of headers with 'name: value' and returns
30
+ * a map of strings representing headers.
31
+ * headersString is all the headers in one string
32
+ * returns a map of strings (as expected by metroplex) representing HTTP
33
+ * request or response headers
34
+ */
35
+ static headersMapFromString(headersString: unknown): Map<string, string>;
36
+ /**
37
+ * For an XHR object, checks the responseType property and handles the response or
38
+ * responseText property accordingly to return a string representation of the response.
39
+ * @returns a string representation of the response, or null if this fails.
40
+ */
41
+ static getResponseStringFromXHR(xhr: WrappedXMLHttpRequest): Promise<any>;
42
+ /** Builds an HTTP Data bundle */
43
+ bundleHTTPData(url: string, rawRequestHeaders: Map<string, string> | undefined, rawRequestPayload: any, rawResponseHeaders: Map<string, string>, rawResponsePayload: any, method: string, isError: boolean): NoSeq<RawHttpData> | null;
44
+ /**
45
+ * Validates a request based on the URL and method. When enabled, will handle
46
+ * de-duping the requests
47
+ */
48
+ isValidRequest(method: unknown): unknown;
49
+ /**
50
+ * Checks two things: that the URL is either on the same domain (or an address relative to the
51
+ * current domain), and also checks that the config http_data_collection flag is enabled.
52
+ * @param {string} url
53
+ * @returns boolean indicating whether the URL passed is either relative (in which case it is
54
+ * inherently on the current domain) or matches the current domain.
55
+ */
56
+ shouldContinueForURL(url: any): boolean;
57
+ /**
58
+ * Determines if the URL is absolute or relative
59
+ * returns boolean indicating whether the URL passed is either absolute or relative
60
+ */
61
+ static isAbsoluteURL(url: unknown): boolean;
62
+ /**
63
+ * Checks whether HTTP payloads can be collected on this URL
64
+ * returns boolean indicating whether HTTP payloads can be collected on this URL
65
+ */
66
+ shouldCollectPayloadForURL(url: any): boolean | undefined;
67
+ /**
68
+ * Double checks content length if we couldn't read the headers, and redacts PII
69
+ * returns the restricted payload
70
+ */
71
+ restrictPayload(payload: unknown, url: string, isError: boolean): string;
72
+ /**
73
+ * Returns true if the content-length header is of acceptable size.
74
+ * Too big gets rejected
75
+ * If the headers are not found, check actual content for length
76
+ */
77
+ contentLengthAcceptable(headers: Map<string, string>, isError: boolean): boolean;
78
+ /**
79
+ * Returns true if the content type according to the headers is valid for collection.
80
+ * Also returns assumed true if content type is not stated in headers.
81
+ * @param {Map} headersMap
82
+ * @returns boolean true if acceptable to collect
83
+ */
84
+ private contentTypeAcceptable;
85
+ /**
86
+ * Returns a descriptive string if we have to drop payload based on the length
87
+ * or type listed in the headers passed. Returns an empty string otherwise.
88
+ */
89
+ getReasonPayloadIsDropped(headers: any, isError: boolean): string;
90
+ /**
91
+ * Returns content length from the headers, if available.
92
+ * If headers are not found or length is not a number, return -1
93
+ */
94
+ contentLength(headersObject: any): number;
95
+ /**
96
+ * Accepts a value that could be any type used as a request payload,
97
+ * and returns a string representation, or null if this fails.
98
+ */
99
+ stringFromRequestBody(value: any, requestHeaders?: Map<string, string>): any;
100
+ /**
101
+ * Removes possible PII from headers.
102
+ * @param {Map} dirtyHeaders a Map of HTTP response or request headers
103
+ * @returns {Map|null} a map of headers with PII redacted
104
+ */
105
+ removePIIHeaders(dirtyHeaders: Map<string, string> | undefined): typeof dirtyHeaders | null;
106
+ }
@@ -1,11 +1,12 @@
1
1
  import { __awaiter } from 'tslib';
2
- import { SEVERITY, CONTENT_TYPE, PII_REDACTION_REPLACEMENT_STRING } from '../../constants.js';
2
+ import { CONTENT_TYPE, PII_REDACTION_REPLACEMENT_STRING } from '../../constants.js';
3
3
  import ClientConfig from '../../api/ClientConfig.js';
4
4
  import StoredMetrics from '../../api/StoredMetrics.js';
5
5
  import { safeFromEntries, safeEntries } from '../../utils/object.js';
6
6
  import { safeTrim, stringifyJSON } from '../../utils/function.js';
7
7
  import { removePII } from '../../utils/piiRedactor.js';
8
8
  import { Singleton } from '../BaseMonitor.js';
9
+ import { Severity } from 'noibu-metroplex-ts-bindings';
9
10
 
10
11
  const DEFAULT_WEBSITE_SUBDOMAIN_PATTERN = /^www\d{0,2}$/;
11
12
  const CONTENT_LENGTH = 'content-length';
@@ -60,7 +61,7 @@ class HTTPDataBundler extends Singleton {
60
61
  this.initialURLPartsReversed.reverse();
61
62
  }
62
63
  catch (e) {
63
- ClientConfig.getInstance().postInternalError({ msg: `Unable to determine hostname for initial URL`, error: e }, false, SEVERITY.warn);
64
+ ClientConfig.getInstance().postInternalError({ msg: `Unable to determine hostname for initial URL`, error: e }, false, Severity.WARN);
64
65
  }
65
66
  }
66
67
  this.httpDataCollectionEnabled = !!ClientConfig.getInstance().enableHttpDataCollection;
@@ -165,7 +166,7 @@ class HTTPDataBundler extends Singleton {
165
166
  return text;
166
167
  }
167
168
  catch (e) {
168
- ClientConfig.getInstance().postInternalError({ msg: `Unable to stringify JSON response`, error: e }, false, SEVERITY.warn);
169
+ ClientConfig.getInstance().postInternalError({ msg: `Unable to stringify JSON response`, error: e }, false, Severity.WARN);
169
170
  return null;
170
171
  }
171
172
  }
@@ -284,7 +285,7 @@ class HTTPDataBundler extends Singleton {
284
285
  ClientConfig.getInstance().postInternalError({
285
286
  msg: `restrictPayload received non string payload`,
286
287
  payloadType: typeof payload,
287
- }, false, SEVERITY.error);
288
+ }, false, Severity.ERROR);
288
289
  return HTTP_BODY_NULL_STRING;
289
290
  }
290
291
  if (payload === HTTP_BODY_NULL_STRING ||
@@ -428,7 +429,7 @@ class HTTPDataBundler extends Singleton {
428
429
  return stringifyJSON(value);
429
430
  }
430
431
  catch (e) {
431
- ClientConfig.getInstance().postInternalError({ msg: `Unable to stringify request body`, error: e }, false, SEVERITY.warn);
432
+ ClientConfig.getInstance().postInternalError({ msg: `Unable to stringify request body`, error: e }, false, Severity.WARN);
432
433
  }
433
434
  return null;
434
435
  }
@@ -0,0 +1,17 @@
1
+ import { NavigationDelegate } from 'react-native-navigation/lib/dist/src/NavigationDelegate';
2
+ import { Singleton } from '../BaseMonitor';
3
+ /** react-native-navigation adapter */
4
+ export declare class ReactNativeNavigationIntegration extends Singleton implements NavigationIntegration {
5
+ private stack;
6
+ private stackPointers;
7
+ private registration;
8
+ /** Attaches provided listeners to the integration */
9
+ register(navigation: NavigationDelegate, onNavigation: (breadcrumbs: string[]) => void): void;
10
+ /**
11
+ * Listens to ComponentWillAppear events, keeps track of visited screens and
12
+ * pops them if the same page is visited to prevent cycles
13
+ */
14
+ private getListener;
15
+ /** Destructor */
16
+ protected destroy(): void;
17
+ }
@@ -0,0 +1,23 @@
1
+ import { Singleton } from '../monitors/BaseMonitor';
2
+ import { EventType, PageVisitEvent, UserStepType } from 'noibu-metroplex-ts-bindings';
3
+ /**
4
+ * Singleton class responsible for debouncing all events
5
+ * that are registered
6
+ */
7
+ export declare class EventDebouncer extends Singleton {
8
+ private readonly debouncePeriods;
9
+ private readonly timeouts;
10
+ private readonly events;
11
+ /** Creates an instance of EventDebouncer */
12
+ constructor();
13
+ /**
14
+ * Creates an event object with the event and the time it was added then pushes
15
+ * that event object to the queue of events waiting to be debounced.
16
+ */
17
+ debounce(event: Omit<PageVisitEvent, 'occ_at'>): void;
18
+ /** Debounce function to be executed once the debounce period is completed */
19
+ sendEvents: (type: EventType | UserStepType) => void;
20
+ /** Sets up the page hide handler to try to push remaining events in the queues */
21
+ _setupUnloadHandler(): void;
22
+ protected destroy(): void;
23
+ }
@@ -0,0 +1,14 @@
1
+ import { NoSeq } from '../types/Metroplex';
2
+ import { PageVisitEventHTTP, RawHttpData } from 'noibu-metroplex-ts-bindings';
3
+ /** Saves the HTTP event to the pageVisit Queue */
4
+ export declare function saveHTTPEvent(httpEvent: Partial<PageVisitEventHTTP>, httpData?: NoSeq<RawHttpData> | null, isGqlError?: boolean): number | undefined;
5
+ /** Determines if a response is a failure */
6
+ export declare function isHttpCodeFailure(code: unknown): boolean;
7
+ /**
8
+ * Checks if sending data is allowed based on the HTTP status code and count.
9
+ * status - The HTTP status code to evaluate.
10
+ * count - The count of events to consider.
11
+ * isGqlError - Whether the context is considered as a GQL error.
12
+ * Returns `true` if sending data is allowed, `false` otherwise.
13
+ */
14
+ export declare function isSendAllowed(status: number, count: number, isGqlError?: boolean): boolean;
@@ -3,9 +3,7 @@ import StoredMetrics from '../api/StoredMetrics.js';
3
3
  import MetroplexSocket from '../api/MetroplexSocket.js';
4
4
  import { safeTrim, getMaxSubstringAllowed, asString } from '../utils/function.js';
5
5
  import { EventDebouncer } from './EventDebouncer.js';
6
- import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
7
- import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
8
- import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
6
+ import { WebsocketMessageType, EventType } from 'noibu-metroplex-ts-bindings';
9
7
 
10
8
  /** @module PageVisitEventHTTP */
11
9
  /** http event manager */
@@ -0,0 +1,31 @@
1
+ import { Singleton } from '../monitors/BaseMonitor';
2
+ import { PageVisitEvent } from 'noibu-metroplex-ts-bindings';
3
+ /**
4
+ * Singleton class to hold all the information
5
+ * about the gathered errors throught the session
6
+ */
7
+ export declare class PageVisitManager extends Singleton {
8
+ partCounter: number;
9
+ pvEvents: PageVisitEvent[];
10
+ pvEventLength: number;
11
+ visibilityChangedCounter: number;
12
+ totalPvEventLength: number;
13
+ /** adds page visit events into the current page visit map and then sends a page visit message
14
+ */
15
+ addPageVisitEvents(eventObjects: PageVisitEvent[]): void;
16
+ /**
17
+ * adds the page visit event into the current page visit map and then sends a page visit message
18
+ * returns the key to access this event in the map
19
+ */
20
+ addPageVisitEvent(eventObj: Omit<PageVisitEvent, 'occ_at'>): void;
21
+ /**
22
+ * adds a new page visit event into the current page visit map and returns the
23
+ * the key to access this event in the map
24
+ */
25
+ _addPageVisitEvent(pvEvent: PageVisitEvent): void;
26
+ /**
27
+ * _sendPageVisitMessage will reset the buffer and post the current
28
+ * content to metroplex
29
+ */
30
+ _sendPageVisitMessage(): void;
31
+ }
@@ -4,8 +4,7 @@ import StoredMetrics from '../api/StoredMetrics.js';
4
4
  import { noibuLog } from '../utils/log.js';
5
5
  import { Singleton } from '../monitors/BaseMonitor.js';
6
6
  import { getOccurredNow } from '../utils/date.js';
7
- import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
8
- import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
7
+ import { WebsocketMessageType } from 'noibu-metroplex-ts-bindings';
9
8
 
10
9
  /** @module Pagevisit */
11
10
  const MAX_PAGEVISIT_EVENTS = 200;
@@ -0,0 +1,12 @@
1
+ import { Option, PageVisitEventError } from 'noibu-metroplex-ts-bindings';
2
+ import { EventInput, PageVisitErrorInput } from '../types/PageVisitErrors';
3
+ /**
4
+ * gets the onURL of a string, defaulting to the location of the webpage
5
+ */
6
+ export declare function getOnURL(realOnURL: unknown): string;
7
+ /**
8
+ * determines if an error is a collect error
9
+ */
10
+ export declare function isErrorCollectedByNoibu(pvError: PageVisitEventError): Promise<false | void>;
11
+ /** Saves the error to the Error queue */
12
+ export declare function saveErrorToPagevisit<T extends PageVisitErrorInput | EventInput>(payload: T, httpDataSeqNum?: Option<number>): void;
@@ -1,13 +1,9 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { isValidURL, getJSStack, stringifyJSON, getMaxSubstringAllowed, asString } from '../utils/function.js';
3
- import { SEVERITY } from '../constants.js';
4
3
  import ClientConfig from '../api/ClientConfig.js';
5
4
  import StoredMetrics from '../api/StoredMetrics.js';
6
5
  import { EventDebouncer } from './EventDebouncer.js';
7
- import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
8
- import { PageVisitErrorSource } from '../node_modules/@noibu/metroplex-ts-bindings/dist/PageVisitErrorSource.js';
9
- import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
10
- import { ErrorType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/ErrorType.js';
6
+ import { PageVisitErrorSource, EventType, Severity, ErrorType } from 'noibu-metroplex-ts-bindings';
11
7
 
12
8
  const BLOCKLISTED_DOMAINS = {
13
9
  'input.noibu.com': true,
@@ -170,7 +166,7 @@ function isErrorCollectedByNoibu(pvError) {
170
166
  // checking if this error originated from the Noibu script
171
167
  const msg = getCollectErrorMsg(pvError);
172
168
  if (msg) {
173
- return ClientConfig.getInstance().postInternalError({ msg, pvError }, false, SEVERITY.error);
169
+ return ClientConfig.getInstance().postInternalError({ msg, pvError }, false, Severity.ERROR);
174
170
  }
175
171
  return false;
176
172
  });
@@ -0,0 +1,67 @@
1
+ import * as React from 'react';
2
+ export type FallbackRender = (errorData: {
3
+ error: Error;
4
+ componentStack: string | null;
5
+ eventId: string | null;
6
+ resetError(): void;
7
+ }) => React.ReactElement;
8
+ export type ErrorBoundaryProps = {
9
+ children?: React.ReactNode | (() => React.ReactNode);
10
+ /**
11
+ * Target fallback component that gets rendered when the error boundary encounters an error.
12
+ *
13
+ * Can either provide a React Component, or a function that returns React Component as
14
+ * a valid fallback prop. If a function is provided, the function will be called with
15
+ * the error, the component stack, and a function that resets the error boundary on error.
16
+ *
17
+ */
18
+ fallback?: React.ReactElement | FallbackRender;
19
+ /** Called when the error boundary encounters an error */
20
+ onError?(error: Error, componentStack: string, eventId: string): void;
21
+ /** Called on componentDidMount() */
22
+ onMount?(): void;
23
+ /** Called if resetError() is called from the fallback render props function */
24
+ onReset?(error: Error | null, componentStack: string | null, eventId: string | null): void;
25
+ /** Called on componentWillUnmount() */
26
+ onUnmount?(error: Error | null, componentStack: string | null, eventId: string | null): void;
27
+ };
28
+ export type ErrorBoundaryState = {
29
+ componentStack: React.ErrorInfo['componentStack'] | null;
30
+ error: Error | null;
31
+ eventId: string | null;
32
+ };
33
+ /**
34
+ * @description Target ErrorBoundary component that logs errors to Noibu. Requires React >= 16.
35
+ * @extends {Component<ErrorBoundaryProps, ErrorBoundaryState>}
36
+ */
37
+ export declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
38
+ state: ErrorBoundaryState;
39
+ /**
40
+ * Lifecycle hook on mount
41
+ * @returns void
42
+ */
43
+ componentDidMount(): void;
44
+ /**
45
+ *
46
+ * Handler for all errors that happen in a wrapped component
47
+ * @param {Error&{cause?:Error}} error
48
+ * @param {React.ErrorInfo} {componentStack}
49
+ * @returns void
50
+ */
51
+ componentDidCatch(error: Error & {
52
+ cause?: Error;
53
+ }, { componentStack }: React.ErrorInfo): void;
54
+ /**
55
+ * * Lifecycle hook on unmount
56
+ * @returns void
57
+ */
58
+ componentWillUnmount(): void;
59
+ /** Callback from fallback to reset the error boundary */
60
+ resetErrorBoundary: () => void;
61
+ /**
62
+ *
63
+ * Renders the fallback ui
64
+ * @returns {React.ReactNode}
65
+ */
66
+ render(): React.ReactNode;
67
+ }
@@ -0,0 +1,50 @@
1
+ import { RecorderEvent } from './nativeSessionRecorderSubscription';
2
+ import { Singleton } from '../monitors/BaseMonitor';
3
+ /** Singleton class to record user sessions */
4
+ export default class SessionRecorder extends Singleton {
5
+ private eventBuffer;
6
+ private vfCounter;
7
+ private didSetupRecorder;
8
+ private isVideoLengthNegativeInvalid;
9
+ private lastFragPostTimestamp;
10
+ private pauseTimeout;
11
+ private lastRecordedTimestamp;
12
+ private firstRecordedTimestamp;
13
+ private recordStopper;
14
+ private freezingEvents;
15
+ /** Setups the SessionRecorder instance for usage */
16
+ constructor();
17
+ /** Sets up the page hide handler to try to push remaining video events */
18
+ setupUnloadHandler(): void;
19
+ /** Sets up the post metrics handler to potentially log a debug message */
20
+ setupPostMetricsHandler(): void;
21
+ /** Starts recording the user session */
22
+ recordUserSession(): Promise<void>;
23
+ /**
24
+ * handleNewRRwebEvent will process each upcoming.
25
+ * rrweb event. It will make sure that the current buffer
26
+ * is updated with the latest events and post the contents
27
+ * of the buffer if it exceeds max size
28
+ */
29
+ handleRecorderEvent(recorderEvent: RecorderEvent): Promise<void>;
30
+ /** Compress event */
31
+ private pack;
32
+ /** Compresses the snapshot */
33
+ private static compress;
34
+ /** builds a log message with debug info */
35
+ buildDebugMessage(eventName: string, totalVideoTime: number, sessionLength: number): string;
36
+ /**
37
+ * handleFragPost communicates with the Metroplex socket
38
+ * to post video fragments when needed. It also handles
39
+ * necessary management of the buffer and it's related
40
+ * variables
41
+ */
42
+ handleFragPost(): Promise<void>;
43
+ /**
44
+ * unfreeze forcefully resumes recording events in case it was frozen
45
+ * waiting for user events
46
+ */
47
+ unfreeze(): Promise<void>;
48
+ /** stops recording */
49
+ private freeze;
50
+ }
@@ -4,14 +4,13 @@ import { LogLevel, initialize, subscribeToNativeEvent } from './nativeSessionRec
4
4
  import StoredMetrics from '../api/StoredMetrics.js';
5
5
  import ClientConfig from '../api/ClientConfig.js';
6
6
  import { stringifyJSON } from '../utils/function.js';
7
- import { SEVERITY, MAX_TIME_FOR_UNSENT_DATA_MILLIS } from '../constants.js';
7
+ import { MAX_TIME_FOR_UNSENT_DATA_MILLIS } from '../constants.js';
8
8
  import MetroplexSocket from '../api/MetroplexSocket.js';
9
9
  import { addSafeEventListener } from '../utils/eventlistener.js';
10
10
  import { noibuLog } from '../utils/log.js';
11
11
  import { Platform } from 'react-native';
12
12
  import { Singleton } from '../monitors/BaseMonitor.js';
13
- import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
14
- import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
13
+ import { Severity, WebsocketMessageType } from 'noibu-metroplex-ts-bindings';
15
14
 
16
15
  // custom event name for posting metrics
17
16
  const POST_METRICS_EVENT_NAME = 'noibuPostMetrics';
@@ -78,7 +77,7 @@ class SessionRecorder extends Singleton {
78
77
  eventName,
79
78
  totalVideoTime,
80
79
  sessionLength,
81
- }, clientDisabled, SEVERITY.warn);
80
+ }, clientDisabled, Severity.WARN);
82
81
  }
83
82
  });
84
83
  }
@@ -147,7 +146,7 @@ class SessionRecorder extends Singleton {
147
146
  // If we don't adjust for time, we assume that the expected video length is
148
147
  // the difference between the first recorded timestamp and the last recorded timestamp.
149
148
  if (this.firstRecordedTimestamp && timestamp < this.firstRecordedTimestamp) {
150
- ClientConfig.getInstance().postInternalError({ msg: `Detected time rewind. Client has been disabled.` }, true, SEVERITY.error, true);
149
+ ClientConfig.getInstance().postInternalError({ msg: `Detected time rewind. Client has been disabled.` }, true, Severity.ERROR, true);
151
150
  return;
152
151
  }
153
152
  const packedEvent = yield this.pack(recorderEvent.message);
@@ -216,7 +215,7 @@ class SessionRecorder extends Singleton {
216
215
  totalVideoTime,
217
216
  'start time': this.firstRecordedTimestamp,
218
217
  'end time': this.lastRecordedTimestamp,
219
- }, false, SEVERITY.error);
218
+ }, false, Severity.ERROR);
220
219
  this.isVideoLengthNegativeInvalid = true;
221
220
  totalVideoTime = 0;
222
221
  }
@@ -243,7 +242,7 @@ class SessionRecorder extends Singleton {
243
242
  }
244
243
  catch (err) {
245
244
  // letting collect know we are closing the rrweb listener
246
- ClientConfig.getInstance().postInternalError({ msg: `video frag socket closed with err: ${err.message}` }, false, SEVERITY.error);
245
+ ClientConfig.getInstance().postInternalError({ msg: `video frag socket closed with err: ${err.message}` }, false, Severity.ERROR);
247
246
  // if we detect an error in the frag posting, we stop recording
248
247
  // the video
249
248
  this.freeze();
@@ -270,7 +269,7 @@ class SessionRecorder extends Singleton {
270
269
  this.recordStopper();
271
270
  }
272
271
  catch (e) {
273
- ClientConfig.getInstance().postInternalError({ msg: `Error during handleFragPost in recordStopper: ${e}` }, false, SEVERITY.error);
272
+ ClientConfig.getInstance().postInternalError({ msg: `Error during handleFragPost in recordStopper: ${e}` }, false, Severity.ERROR);
274
273
  }
275
274
  }
276
275
  }
@@ -0,0 +1,77 @@
1
+ /** The level of logging to show in the device logcat stream. */
2
+ export declare enum LogLevel {
3
+ Verbose = "Verbose",
4
+ Debug = "Debug",
5
+ Info = "Info",
6
+ Warning = "Warning",
7
+ Error = "Error",
8
+ None = "None"
9
+ }
10
+ /**
11
+ * The configuration that will be used to customize the session recording behaviour.
12
+ *
13
+ * @param userId [OPTIONAL default = null] Target custom identifier for the current user. If passed as null, the user id
14
+ * will be auto generated. The user id in general is sticky across sessions.
15
+ * The provided user id must follow these conditions:
16
+ * 1. Cannot be an empty string.
17
+ * 2. Should be base36 and smaller than "1Z141Z4".
18
+ * @param logLevel [OPTIONAL default = LogLevel.None] The level of logging to show in the device logcat stream.
19
+ * @param allowMeteredNetworkUsage [OPTIONAL default = false] Allows uploading session data to the servers on device metered network.
20
+ * @param enableWebViewCapture [OPTIONAL default = true] Allows Noibu - Session recorder to capture the web views DOM content.
21
+ * @param allowedDomains [OPTIONAL default = ["*"]] The whitelisted domains to allow Noibu - Session recorder to capture their DOM content.
22
+ * If it contains "*" as an element, all domains will be captured.
23
+ * @param disableOnLowEndDevices [OPTIONAL default = false] Disable Noibu - Session recorder on low-end devices.
24
+ * @param maximumDailyNetworkUsageInMB [OPTIONAL default = null] Maximum daily network usage for Noibu - Session recorder (null = No limit). When the limit is reached, Noibu - Session recorder will turn on lean mode.
25
+ */
26
+ export interface SessionRecorderConfig {
27
+ userId?: string | null;
28
+ logLevel?: LogLevel;
29
+ allowMeteredNetworkUsage?: boolean;
30
+ enableWebViewCapture?: boolean;
31
+ allowedDomains?: string[];
32
+ disableOnLowEndDevices?: boolean;
33
+ maximumDailyNetworkUsageInMB?: number;
34
+ }
35
+ /**
36
+ * Initializes the Noibu - Session recording SDK if the API level is supported.
37
+ * param projectId [REQUIRED] The session recording project id to send data to.
38
+ * param config [OPTIONAL] The sessionreplay config, if not provided default values are used.
39
+ */
40
+ export declare function initialize(projectId: string, config?: SessionRecorderConfig): void;
41
+ /**
42
+ * Sets a custom user id that can be used to identify the user. It has less
43
+ * restrictions than the userId parameter. You can pass any string and
44
+ * you can filter on it on the dashboard side. If you need the most efficient
45
+ * filtering on the dashboard, use the userId parameter if possible.
46
+ * <p>
47
+ * Note: custom user id cannot be null or empty, or consists only of whitespaces.
48
+ * </p>
49
+ * @param customUserId The custom user id to set.
50
+ */
51
+ export declare function setCustomUserId(customUserId: string): void;
52
+ /**
53
+ * Sets a custom session id that can be used to identify the session.
54
+ * <p>
55
+ * Note: custom session id cannot be null or empty, or consists only of whitespaces.
56
+ * </p>
57
+ * @param customSessionId The custom session id to set.
58
+ */
59
+ export declare function setCustomSessionId(customSessionId: string): void;
60
+ export type RecorderEvent = import('./types').RecorderEvent;
61
+ export type UnsubscribeFn = import('./types').UnsubscribeFn;
62
+ /**
63
+ * Subscribes to a native event emitted by the Noibu Session Recorder.
64
+ *
65
+ * This function listens for the `noibuRecordingEvent` emitted from the native layer (only on Android)
66
+ * and invokes the provided callback whenever the event occurs. If the platform is not Android,
67
+ * the function will do nothing and return a no-op unsubscribe function.
68
+ *
69
+ * @param {function(RecorderEvent): void} callback - Target callback function that will be invoked with
70
+ * the event data whenever the `noibuRecordingEvent` is emitted.
71
+ *
72
+ * @returns {UnsubscribeFn} Target function to unsubscribe from the event. On Android, this will remove
73
+ * the event listener. On other platforms, it will be a no-op.
74
+ *
75
+ * @throws {Error} If the Noibu Session Recorder is not initialized before calling this function.
76
+ */
77
+ export declare function subscribeToNativeEvent(callback: (event: RecorderEvent) => void): UnsubscribeFn;
@@ -0,0 +1,91 @@
1
+ type Color = {
2
+ a: number;
3
+ b: number;
4
+ r: number;
5
+ g: number;
6
+ };
7
+ type Paint = {
8
+ strokeJoin: number;
9
+ strokeWidth: number;
10
+ strokeCap: number;
11
+ color: Color;
12
+ dither: boolean;
13
+ blendMode: number;
14
+ style: number;
15
+ antiAlias: boolean;
16
+ strokeMiter: number;
17
+ };
18
+ type Rect = {
19
+ top: number;
20
+ left: number;
21
+ bottom: number;
22
+ right: number;
23
+ };
24
+ type Command = {
25
+ name?: string;
26
+ id?: number;
27
+ type: string;
28
+ isClipRectSource?: boolean;
29
+ rect?: Rect;
30
+ paintIndex?: number;
31
+ op?: number;
32
+ antiAlias?: boolean;
33
+ matrix?: number[];
34
+ };
35
+ type ViewNode = {
36
+ viewX: number;
37
+ visible: boolean;
38
+ processedText$delegate: {
39
+ _value: any;
40
+ initializer: any;
41
+ };
42
+ viewY: number;
43
+ viewWidth: number;
44
+ clickable: boolean;
45
+ viewHeight: number;
46
+ isMasked: boolean;
47
+ type: string;
48
+ renderNodeId: number;
49
+ isWebView: boolean;
50
+ ignoreClicks: boolean;
51
+ children: ViewNode[];
52
+ width: number;
53
+ x: number;
54
+ y: number;
55
+ id: number;
56
+ text: string;
57
+ height: number;
58
+ backgroundColor?: number;
59
+ };
60
+ type ViewHierarchy = {
61
+ root: ViewNode;
62
+ visibleFragments: any[];
63
+ timestamp: number;
64
+ };
65
+ type SubPicture = {
66
+ subPictures: any[];
67
+ images: any[];
68
+ screenWidth: number;
69
+ textBlobs: any[];
70
+ density: number;
71
+ vertices: any[];
72
+ screenHeight: number;
73
+ activityName: string;
74
+ paints: Paint[];
75
+ typefaces: any[];
76
+ viewHierarchy: ViewHierarchy;
77
+ paths: any[];
78
+ activityHashCode: number;
79
+ commands: Command[];
80
+ timestamp: number;
81
+ };
82
+ export type RecorderEvent = {
83
+ message: NativeFrames;
84
+ };
85
+ export type NativeFrames = {
86
+ p: (number | boolean | SubPicture)[][];
87
+ a: (number[] | (number | string | string[])[])[];
88
+ e: (string | number)[];
89
+ };
90
+ export type UnsubscribeFn = () => void;
91
+ export {};