Skip to content

Commit cf9dc51

Browse files
committed
feat(breadcrumbs): ✨ timstamp as number outside of breadcrumbs
1 parent b285153 commit cf9dc51

File tree

5 files changed

+52
-10
lines changed

5 files changed

+52
-10
lines changed

packages/replay/src/coreHandlers/handleClick.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ import { addBreadcrumbEvent } from './util/addBreadcrumbEvent';
1616
import { getClosestInteractive } from './util/domUtils';
1717
import { onWindowOpen } from './util/onWindowOpen';
1818

19-
type ClickBreadcrumb = Breadcrumb & {
20-
timestamp: number;
21-
};
19+
type ClickBreadcrumb = Breadcrumb;
2220

2321
interface Click {
2422
timestamp: number;
@@ -114,8 +112,12 @@ export class ClickDetector implements ReplayClickDetector {
114112
return;
115113
}
116114

115+
const timestampAsNumber = typeof breadcrumb.timestamp === 'string'
116+
? new Date(breadcrumb.timestamp).getTime()
117+
: breadcrumb.timestamp || 0;
118+
117119
const newClick: Click = {
118-
timestamp: timestampToS(breadcrumb.timestamp),
120+
timestamp: timestampToS(timestampAsNumber),
119121
clickBreadcrumb: breadcrumb,
120122
// Set this to 0 so we know it originates from the click breadcrumb
121123
clickCount: 0,
@@ -209,6 +211,9 @@ export class ClickDetector implements ReplayClickDetector {
209211

210212
const isSlowClick = !hadScroll && !hadMutation;
211213
const { clickCount, clickBreadcrumb } = click;
214+
const timestampAsNumber = typeof clickBreadcrumb.timestamp === 'string'
215+
? new Date(clickBreadcrumb.timestamp).getTime()
216+
: clickBreadcrumb.timestamp || 0;
212217

213218
// Slow click
214219
if (isSlowClick) {
@@ -220,7 +225,7 @@ export class ClickDetector implements ReplayClickDetector {
220225
const breadcrumb: ReplaySlowClickFrame = {
221226
type: 'default',
222227
message: clickBreadcrumb.message,
223-
timestamp: clickBreadcrumb.timestamp,
228+
timestamp: timestampAsNumber,
224229
category: 'ui.slowClickDetected',
225230
data: {
226231
...clickBreadcrumb.data,
@@ -243,7 +248,7 @@ export class ClickDetector implements ReplayClickDetector {
243248
const breadcrumb: ReplayMultiClickFrame = {
244249
type: 'default',
245250
message: clickBreadcrumb.message,
246-
timestamp: clickBreadcrumb.timestamp,
251+
timestamp: timestampAsNumber,
247252
category: 'ui.multiClick',
248253
data: {
249254
...clickBreadcrumb.data,

packages/replay/src/coreHandlers/util/addBreadcrumbEvent.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ export function addBreadcrumbEvent(replay: ReplayContainer, breadcrumb: Breadcru
1919
}
2020

2121
replay.addUpdate(() => {
22+
const timestampAsNumber = typeof breadcrumb.timestamp === 'string'
23+
? new Date(breadcrumb.timestamp).getTime() / 1000
24+
: breadcrumb.timestamp || 0;
25+
2226
// This should never reject
2327
// eslint-disable-next-line @typescript-eslint/no-floating-promises
2428
replay.throttledAddEvent({
2529
type: EventType.Custom,
2630
// TODO: We were converting from ms to seconds for breadcrumbs, spans,
2731
// but maybe we should just keep them as milliseconds
28-
timestamp: (breadcrumb.timestamp || 0) * 1000,
32+
timestamp: timestampAsNumber * 1000,
2933
data: {
3034
tag: 'breadcrumb',
3135
// normalize to max. 10 depth and 1_000 properties per object

packages/replay/src/replay.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,10 +700,13 @@ export class ReplayContainer implements ReplayContainerInterface {
700700
});
701701

702702
this.addUpdate(() => {
703+
const timestampAsNumber = typeof breadcrumb.timestamp === 'string'
704+
? new Date(breadcrumb.timestamp).getTime()
705+
: breadcrumb.timestamp || 0;
703706
// Return `false` if the event _was_ added, as that means we schedule a flush
704707
return !addEventSync(this, {
705708
type: ReplayEventTypeCustom,
706-
timestamp: breadcrumb.timestamp || 0,
709+
timestamp: timestampAsNumber,
707710
data: {
708711
tag: 'breadcrumb',
709712
payload: breadcrumb,
@@ -1003,11 +1006,14 @@ export class ReplayContainer implements ReplayContainerInterface {
10031006
*/
10041007
private _createCustomBreadcrumb(breadcrumb: ReplayBreadcrumbFrame): void {
10051008
this.addUpdate(() => {
1009+
const timestampAsNumber = typeof breadcrumb.timestamp === 'string'
1010+
? new Date(breadcrumb.timestamp).getTime()
1011+
: breadcrumb.timestamp || 0;
10061012
// This should never reject
10071013
// eslint-disable-next-line @typescript-eslint/no-floating-promises
10081014
this.throttledAddEvent({
10091015
type: EventType.Custom,
1010-
timestamp: breadcrumb.timestamp || 0,
1016+
timestamp: timestampAsNumber,
10111017
data: {
10121018
tag: 'breadcrumb',
10131019
payload: breadcrumb,

packages/replay/src/types/replayFrame.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type { ReplayEventTypeCustom } from './rrweb';
1414
type AnyRecord = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any
1515

1616
interface ReplayBaseBreadcrumbFrame {
17-
timestamp: number;
17+
timestamp: number | string;
1818
/**
1919
* For compatibility reasons
2020
*/

packages/replay/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,31 @@ describe('Unit | coreHandlers | util | addBreadcrumbEvent', function () {
4747
},
4848
]);
4949
});
50+
51+
it('handles timestamp as string', async () => {
52+
const baseTimestampAsISOString = new Date(BASE_TIMESTAMP).toISOString()
53+
const breadcrumb: any = {
54+
category: 'console',
55+
message: 'Test message with timestamp as string',
56+
timestamp: baseTimestampAsISOString,
57+
};
58+
59+
const replay = setupReplayContainer();
60+
addBreadcrumbEvent(replay, breadcrumb);
61+
62+
expect((replay.eventBuffer as EventBufferArray).events).toEqual([
63+
{
64+
type: 5,
65+
timestamp: BASE_TIMESTAMP,
66+
data: {
67+
tag: 'breadcrumb',
68+
payload: {
69+
category: 'console',
70+
message: 'Test message with timestamp as string',
71+
timestamp: baseTimestampAsISOString,
72+
},
73+
},
74+
},
75+
]);
76+
});
5077
});

0 commit comments

Comments
 (0)