Skip to content

Commit e0df729

Browse files
committed
feat: Add browser-telemetry API types.
1 parent 59cd352 commit e0df729

File tree

6 files changed

+322
-0
lines changed

6 files changed

+322
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
export type BreadcrumbClass =
2+
| 'custom'
3+
| 'log'
4+
| 'navigation'
5+
| 'feature-management'
6+
| 'ui'
7+
| 'http';
8+
9+
export type BreadcrumbLevel = 'error' | 'warning' | 'info' | 'debug';
10+
11+
export type BreadcrumbDataValue = boolean | number | string;
12+
13+
export type BreadcrumbData = Record<string, BreadcrumbDataValue>;
14+
15+
export interface Breadcrumb {
16+
/**
17+
* The class of the breadcrumb. This is the top level categorization of breadcrumbs.
18+
*/
19+
class: BreadcrumbClass;
20+
21+
/**
22+
* When the event associated with the breadcrumb happened. The timestamp is in milliseconds since January 1, 1970
23+
* Universal Coordinated Time (UTC)
24+
*
25+
* For most breadcrumbs this will not be different than the time of breadcrumb creation, but if there is a delay
26+
* between the event and breadcrumb capture, then the time of the event should be used instead.
27+
*/
28+
timestamp: number;
29+
30+
/**
31+
* The level of severity of the breadcrumb. The default choice of level should be `info` if there isn't a clear
32+
* reason to use a different level.
33+
*/
34+
level: BreadcrumbLevel;
35+
36+
/**
37+
* The type of the breadcrumb. Each class may be split into multiple types with the type more specifically
38+
* categorizing the type of event.
39+
*/
40+
type?: string;
41+
42+
/**
43+
* A message associated with the breadcrumb.
44+
*/
45+
message?: string;
46+
47+
/**
48+
* Any data associated with the breadcrumb.
49+
*/
50+
data?: BreadcrumbData;
51+
}
52+
53+
type ImplementsCrumb<U extends Breadcrumb> = U;
54+
55+
export type CustomBreadcrumb = ImplementsCrumb<{
56+
class: 'custom';
57+
timestamp: number;
58+
level: BreadcrumbLevel;
59+
type?: string;
60+
message?: string;
61+
data?: BreadcrumbData;
62+
}>;
63+
64+
export type LogBreadcrumb = ImplementsCrumb<{
65+
class: 'log';
66+
timestamp: number;
67+
level: BreadcrumbLevel;
68+
message: string;
69+
data?: BreadcrumbData;
70+
}>;
71+
72+
export type NavigationBreadcrumb = ImplementsCrumb<{
73+
class: 'navigation';
74+
timestamp: number;
75+
level: 'info';
76+
type?: string;
77+
data?: {
78+
/**
79+
* The location being navigated from. In a web application this would typically be a URL.
80+
*/
81+
from?: string;
82+
/**
83+
* The location being navigated to. In a web application this would typically be a URL.
84+
*/
85+
to?: string;
86+
};
87+
}>;
88+
89+
export type FeatureManagementBreadcrumb = ImplementsCrumb<{
90+
class: 'feature-management';
91+
timestamp: number;
92+
level: 'info';
93+
type: 'flag-evaluated' | 'flag-detail-changed';
94+
data?: {
95+
/**
96+
* The flag key.
97+
*/
98+
key?: string;
99+
// Not supporting JSON flags in breadcrumbs. As noted in design we may want to eventually support none of the
100+
// values in the breadcrumb.
101+
/**
102+
* The evaluated value for simple types.
103+
*/
104+
value?: boolean | string | number;
105+
};
106+
}>;
107+
108+
export type UiBreadcrumb = ImplementsCrumb<{
109+
class: 'ui';
110+
timestamp: number;
111+
level: 'info';
112+
type: 'click' | 'input';
113+
message: string;
114+
}>;
115+
116+
export type HttpBreadcrumb = ImplementsCrumb<{
117+
class: 'http';
118+
timestamp: number;
119+
level: 'error' | 'info'; // Error if an error status code?
120+
type: 'xhr' | 'fetch';
121+
data?: {
122+
url?: string;
123+
method?: string;
124+
statusCode: number;
125+
statusText: string;
126+
};
127+
}>;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { LDClient, LDInspection } from 'launchdarkly-js-client-sdk';
2+
3+
import { Breadcrumb } from './Breadcrumb';
4+
import { EventData } from './EventData';
5+
6+
// TODO: Make a core client-side telemetry package.
7+
// TODO: Put all the interfaces in the core package and only browser auto telemetry in the
8+
// browser package.
9+
10+
export interface BrowserTelemetry {
11+
inspectors(): LDInspection[];
12+
13+
captureError(exception: Error): void;
14+
captureErrorEvent(errorEvent: ErrorEvent): void;
15+
captureSession(sessionEvent: EventData): void;
16+
17+
addBreadcrumb(breadcrumb: Breadcrumb): void;
18+
19+
register(client: LDClient): void;
20+
21+
close(): void;
22+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { type LDContext, type LDEvaluationDetail } from 'launchdarkly-js-client-sdk';
2+
3+
import { BrowserTelemetry } from './BrowserTelemetry';
4+
5+
export interface Collector {
6+
register(telemetry: BrowserTelemetry, sessionId: string): void;
7+
unregister(): void;
8+
9+
handleFlagUsed?(flagKey: string, flagDetail: LDEvaluationDetail, _context: LDContext): void;
10+
handleFlagDetailChanged?(flagKey: string, detail: LDEvaluationDetail): void;
11+
// TODO: Should have an ID to correlate to.
12+
handleErrorEvent?(name: string, message: string): void;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import StackTrace from '../stack/StackTrace';
2+
import { Breadcrumb } from './Breadcrumb';
3+
4+
export interface ErrorData {
5+
type: string;
6+
message: string;
7+
stack: StackTrace;
8+
breadcrumbs: Breadcrumb[];
9+
sessionId: string;
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface EventData {
2+
// TODO: Change this to be a union of the different data types.
3+
[key: string]: any;
4+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { Collector } from './Collector';
2+
3+
/**
4+
* Interface for URL filters.
5+
*
6+
* Given a URL the filter may return a different string to represent that URL.
7+
* This string will be included in the telemetry events instead of the original.
8+
*
9+
* The URL will be filtered by SDK internal filters before this function is called.
10+
*
11+
* To redact a URL entirely return an empty string.
12+
*
13+
* Example:
14+
* customUrlFilter: (url) => {
15+
* if (url.includes('secret')) {
16+
* return ''
17+
* }
18+
* return url;
19+
* }
20+
*/
21+
export interface UrlFilter {
22+
(url: string): string;
23+
}
24+
25+
export interface HttpBreadCrumbOptions {
26+
/**
27+
* If fetch should be instrumented and breadcrumbs included for fetch requests.
28+
*
29+
* Defaults to true.
30+
*/
31+
instrumentFetch?: boolean;
32+
33+
/**
34+
* If XMLHttpRequests should be instrumented and breadcrumbs included for XMLHttpRequests.
35+
*
36+
* Defaults to true.
37+
*/
38+
instrumentXhr?: boolean;
39+
40+
/**
41+
* Customize URL filtering. This will be applied in addition to some baseline filtering included
42+
* which redacts components of LaunchDarkly URLs.
43+
*/
44+
customUrlFilter?: UrlFilter;
45+
}
46+
47+
export interface StackOptions {
48+
/**
49+
* Configuration that controls how source is captured.
50+
*/
51+
source?: {
52+
/**
53+
* The number of lines captured before the originating line.
54+
*
55+
* Defaults to 3.
56+
*/
57+
beforeLines?: number;
58+
/**
59+
* The number of lines captured after the originating line.
60+
*
61+
* Defaults to 3.
62+
*/
63+
afterLines?: number;
64+
65+
/**
66+
* The maximum length of source line to include. Lines longer than this will be
67+
* trimmed.
68+
*
69+
* Defaults to 280.
70+
*/
71+
maxLineLength?: number;
72+
};
73+
}
74+
75+
/**
76+
* Options for configuring browser telemetry.
77+
*/
78+
export interface Options {
79+
/**
80+
* The maximum number of pending events. Events may be captured before the LaunchDarkly
81+
* SDK is initialized and these are stored until they can be sent. This only affects the
82+
* events captured during initialization.
83+
*/
84+
maxPendingEvents?: number;
85+
/**
86+
* Properties related to automatic breadcrumb collection.
87+
*/
88+
breadcrumbs?: {
89+
/**
90+
* Set the maximum number of breadcrumbs. Defaults to 50.
91+
*/
92+
maxBreadcrumbs?: number;
93+
94+
/**
95+
* True to enable automatic evaluation breadcrumbs. Defaults to true.
96+
*/
97+
evaluations?: boolean;
98+
99+
/**
100+
* True to enable flag change breadcrumbs. Defaults to true.
101+
*/
102+
flagChange?: boolean;
103+
104+
/**
105+
* True to enable click breadcrumbs. Defaults to true.
106+
*/
107+
click?: boolean;
108+
109+
/**
110+
* True to enable input breadcrumbs for keypresses. Defaults to true.
111+
*
112+
* Input breadcrumbs do not include entered text, just that text was entered.
113+
*/
114+
keyboardInput?: boolean;
115+
116+
/**
117+
* Controls instrumentation and breadcrumbs for HTTP requests.
118+
* The default is to instrument XMLHttpRequests and fetch requests.
119+
*
120+
* `false` to disable all HTTP breadcrumbs and instrumentation.
121+
*
122+
* Example:
123+
* ```
124+
* // This would instrument only XmlHttpRequests
125+
* http: {
126+
* instrumentFetch: false
127+
* instrumentXhr: true
128+
* }
129+
*
130+
* // Disable all HTTP instrumentation:
131+
* http: false
132+
* ```
133+
*/
134+
http?: HttpBreadCrumbOptions | false;
135+
};
136+
137+
/**
138+
* Additional, or custom, collectors.
139+
*/
140+
collectors?: Collector[];
141+
142+
/**
143+
* Configuration that controls the capture of the stack trace.
144+
*/
145+
stack?: StackOptions;
146+
}

0 commit comments

Comments
 (0)