@brett_lamy/docstream 1.6.0 → 1.7.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/README.md +34 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/replay/ReplayPlayer.d.ts +64 -0
- package/dist/replay/ReplayPlayer.d.ts.map +1 -0
- package/dist/replay/ReplayPlayer.js +211 -0
- package/dist/replay/ReplayPlayer.js.map +1 -0
- package/dist/replay/ReplayPreview.d.ts +24 -12
- package/dist/replay/ReplayPreview.d.ts.map +1 -1
- package/dist/replay/ReplayPreview.js +37 -32
- package/dist/replay/ReplayPreview.js.map +1 -1
- package/dist/replay/ReplayStage.d.ts +1 -1
- package/dist/replay/ReplayStage.js +1 -1
- package/dist/replay/ReplayStageImpl.js +1 -1
- package/dist/replay/ReplayStageImpl.js.map +1 -1
- package/dist/replay/demo/index.d.ts +3 -0
- package/dist/replay/demo/index.d.ts.map +1 -0
- package/dist/replay/demo/index.js +66 -0
- package/dist/replay/demo/index.js.map +1 -0
- package/dist/replay/index.d.ts +2 -2
- package/dist/replay/index.d.ts.map +1 -1
- package/dist/replay/index.js +1 -1
- package/dist/replay/index.js.map +1 -1
- package/dist/replay/types.js +3 -3
- package/dist/replay/types.js.map +1 -1
- package/dist/styles.css +565 -75
- package/package.json +8 -6
- package/src/index.ts +2 -1
- package/src/replay/ReplayPlayer.tsx +430 -0
- package/src/replay/ReplayPreview.tsx +111 -85
- package/src/replay/ReplayStage.tsx +1 -1
- package/src/replay/ReplayStageImpl.tsx +1 -1
- package/src/replay/demo/index.ts +67 -0
- package/src/replay/index.ts +6 -1
- package/src/replay/types.ts +3 -3
- package/src/styles.css +565 -75
- package/dist/replay/NativeReplay.d.ts +0 -9
- package/dist/replay/NativeReplay.d.ts.map +0 -1
- package/dist/replay/NativeReplay.js +0 -175
- package/dist/replay/NativeReplay.js.map +0 -1
- package/src/replay/NativeReplay.tsx +0 -240
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState, type CSSProperties, type ReactNode } from 'react';
|
|
2
|
+
import { BrowserBar, ReplayPlayer } from './ReplayPlayer';
|
|
3
|
+
import type { ReplayPlayerOptions, ReplayPreviewHandle } from './ReplayPlayer';
|
|
2
4
|
import type { ReplayEvent } from './types';
|
|
3
5
|
import { normalizeReplayEmbedUrl } from './url';
|
|
4
6
|
|
|
7
|
+
export { formatReplayTime } from './ReplayPlayer';
|
|
8
|
+
export type { ReplayChrome, ReplayPlayerOptions, ReplayPreviewHandle } from './ReplayPlayer';
|
|
9
|
+
|
|
5
10
|
export interface ReplayPageSource {
|
|
6
11
|
kind: 'url';
|
|
7
12
|
url: string;
|
|
@@ -26,21 +31,25 @@ export type ReplaySource =
|
|
|
26
31
|
| ReplayEventsSource
|
|
27
32
|
| ReplayEventsUrlSource;
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
source: ReplaySource;
|
|
32
|
-
/** Avoid mounting the rrweb player until the editor block is visible. */
|
|
34
|
+
interface ReplayPreviewCommon extends ReplayPlayerOptions {
|
|
35
|
+
/** Keep the player unmounted (a placeholder frame) until true, e.g. until an editor block is visible. */
|
|
33
36
|
active?: boolean;
|
|
34
|
-
/** Public-page embeds default to lazy loading; native rrweb playback defaults to paused. */
|
|
35
|
-
autoplay?: boolean;
|
|
36
|
-
loop?: boolean;
|
|
37
|
-
className?: string;
|
|
38
|
-
title?: string;
|
|
39
|
-
/** Playback speed options mirror the Loop QA player. */
|
|
40
|
-
speeds?: number[];
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
/** Play an rrweb recording you already hold. */
|
|
40
|
+
export interface ReplayPreviewEventsProps extends ReplayPreviewCommon {
|
|
41
|
+
events: ReplayEvent[];
|
|
42
|
+
source?: undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Embed a public Loop QA URL, a public event endpoint, or an in-memory rrweb event list. */
|
|
46
|
+
export interface ReplayPreviewSourceProps extends ReplayPreviewCommon {
|
|
47
|
+
source: ReplaySource;
|
|
48
|
+
events?: undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Pass `events` (the player API) or `source` (the embed API): both render the same player. */
|
|
52
|
+
export type ReplayPreviewProps = ReplayPreviewEventsProps | ReplayPreviewSourceProps;
|
|
44
53
|
|
|
45
54
|
function sourcePage(source: ReplaySource): ReplayPageSource | null {
|
|
46
55
|
if (typeof source === 'string') return { kind: 'url', url: source };
|
|
@@ -59,50 +68,64 @@ function sourceEventsUrl(source: ReplaySource): ReplayEventsUrlSource | null {
|
|
|
59
68
|
return source.kind === 'events-url' ? source : null;
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
/** The frame around a non-player body (an iframe, a loading or error note): same root, same chrome hooks. */
|
|
72
|
+
function Frame({
|
|
73
|
+
kind, chrome, className, title, href, trafficLights = true, ar, style, children,
|
|
74
|
+
}: {
|
|
75
|
+
kind: string;
|
|
76
|
+
chrome: NonNullable<ReplayPlayerOptions['chrome']>;
|
|
77
|
+
className?: string;
|
|
78
|
+
title?: string;
|
|
79
|
+
href?: string;
|
|
80
|
+
trafficLights?: boolean;
|
|
81
|
+
ar?: string;
|
|
82
|
+
style?: CSSProperties;
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
}) {
|
|
71
85
|
return (
|
|
72
|
-
<
|
|
73
|
-
className=
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
<div
|
|
87
|
+
className={className ? `replay-preview ${className}` : 'replay-preview'}
|
|
88
|
+
data-slot="replay-preview"
|
|
89
|
+
data-replay-preview={kind}
|
|
90
|
+
data-chrome={chrome}
|
|
91
|
+
data-fit="width"
|
|
92
|
+
style={style}
|
|
93
|
+
{...(title ? { role: 'group', 'aria-label': title } : null)}
|
|
94
|
+
>
|
|
95
|
+
{chrome === 'browser' ? <BrowserBar href={href ?? ''} trafficLights={trafficLights} loading={false} /> : null}
|
|
96
|
+
<div data-slot="replay-preview-stage" style={ar ? ({ '--replay-ar': ar } as CSSProperties) : undefined}>
|
|
97
|
+
{children}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
81
100
|
);
|
|
82
101
|
}
|
|
83
102
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
function ReplayFrame({
|
|
104
|
+
source, title, chrome = 'minimal', className, style, trafficLights,
|
|
105
|
+
}: { source: ReplayPageSource } & Pick<ReplayPlayerOptions, 'title' | 'chrome' | 'className' | 'style' | 'trafficLights'>) {
|
|
106
|
+
const url = normalizeReplayEmbedUrl(source.url);
|
|
88
107
|
return (
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
<Frame kind="iframe" chrome={chrome} className={className} style={style} href={url ?? source.url} trafficLights={trafficLights} ar="16 / 9">
|
|
109
|
+
{url ? (
|
|
110
|
+
<iframe
|
|
111
|
+
className="replay-preview__frame"
|
|
112
|
+
src={url}
|
|
113
|
+
title={title ?? source.title ?? 'Replay preview'}
|
|
114
|
+
loading="lazy"
|
|
115
|
+
allow="autoplay; fullscreen"
|
|
116
|
+
allowFullScreen
|
|
117
|
+
referrerPolicy="strict-origin-when-cross-origin"
|
|
118
|
+
/>
|
|
119
|
+
) : (
|
|
120
|
+
<a className="replay-preview__invalid" href={source.url} target="_blank" rel="noreferrer">
|
|
121
|
+
Open replay
|
|
122
|
+
</a>
|
|
123
|
+
)}
|
|
124
|
+
</Frame>
|
|
92
125
|
);
|
|
93
126
|
}
|
|
94
127
|
|
|
95
|
-
function RemoteReplay({
|
|
96
|
-
source,
|
|
97
|
-
autoplay,
|
|
98
|
-
loop,
|
|
99
|
-
speeds,
|
|
100
|
-
}: {
|
|
101
|
-
source: ReplayEventsUrlSource;
|
|
102
|
-
autoplay?: boolean;
|
|
103
|
-
loop?: boolean;
|
|
104
|
-
speeds?: number[];
|
|
105
|
-
}) {
|
|
128
|
+
function RemoteReplay({ source, options }: { source: ReplayEventsUrlSource; options: ReplayPlayerOptions }) {
|
|
106
129
|
const [events, setEvents] = useState<ReplayEvent[] | null>(null);
|
|
107
130
|
const [error, setError] = useState<string | null>(null);
|
|
108
131
|
|
|
@@ -130,48 +153,51 @@ function RemoteReplay({
|
|
|
130
153
|
return () => controller.abort();
|
|
131
154
|
}, [source.url, source.fetchInit]);
|
|
132
155
|
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
if (events) return <ReplayPlayer {...options} events={events} />;
|
|
157
|
+
return (
|
|
158
|
+
<Frame kind="rrweb" chrome={options.chrome ?? 'browser'} className={options.className} style={options.style} href={options.url} trafficLights={options.trafficLights} ar="16 / 9">
|
|
159
|
+
{error ? (
|
|
160
|
+
<div className="replay-preview__error" role="alert">{error}</div>
|
|
161
|
+
) : (
|
|
162
|
+
<div className="replay-preview__empty">Loading replay…</div>
|
|
163
|
+
)}
|
|
164
|
+
</Frame>
|
|
165
|
+
);
|
|
136
166
|
}
|
|
137
167
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const page = sourcePage(source);
|
|
150
|
-
const events = sourceEvents(source);
|
|
151
|
-
const eventsUrl = sourceEventsUrl(source);
|
|
152
|
-
const rootClass = `replay-preview ${className ?? ''}`.trim();
|
|
153
|
-
|
|
154
|
-
if (page) {
|
|
155
|
-
return (
|
|
156
|
-
<div className={rootClass} data-replay-preview="iframe">
|
|
157
|
-
<ReplayFrame source={page} title={title} />
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
if (events) {
|
|
168
|
+
/**
|
|
169
|
+
* A session replay in a browser frame. Pass `events` (an rrweb recording) to play it with the full player:
|
|
170
|
+
* URL bar, poster, scrubber with markers, pointer overlay, keyboard map, fullscreen. Or pass `source` (a
|
|
171
|
+
* public Loop QA URL, an events URL, or an event list), which renders the same player, or an iframe for
|
|
172
|
+
* page URLs. rrweb loads on first render of an event player, never for iframes.
|
|
173
|
+
*/
|
|
174
|
+
export function ReplayPreview(props: ReplayPreviewProps) {
|
|
175
|
+
const { active = true, source, events, ...options } = props;
|
|
176
|
+
const { chrome, className, style } = options;
|
|
177
|
+
|
|
178
|
+
if (!active) {
|
|
162
179
|
return (
|
|
163
|
-
<div
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
<div
|
|
181
|
+
className={className ? `replay-preview ${className}` : 'replay-preview'}
|
|
182
|
+
data-slot="replay-preview"
|
|
183
|
+
data-replay-preview="paused"
|
|
184
|
+
data-chrome={chrome ?? 'minimal'}
|
|
185
|
+
style={style}
|
|
186
|
+
/>
|
|
166
187
|
);
|
|
167
188
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
189
|
+
|
|
190
|
+
if (events) return <ReplayPlayer {...options} events={events} />;
|
|
191
|
+
if (source === undefined) return null;
|
|
192
|
+
|
|
193
|
+
const page = sourcePage(source);
|
|
194
|
+
if (page) {
|
|
195
|
+
return <ReplayFrame source={page} title={options.title} chrome={chrome} className={className} style={style} trafficLights={options.trafficLights} />;
|
|
174
196
|
}
|
|
197
|
+
const list = sourceEvents(source);
|
|
198
|
+
if (list) return <ReplayPlayer {...options} events={list.events} />;
|
|
199
|
+
const remote = sourceEventsUrl(source);
|
|
200
|
+
if (remote) return <RemoteReplay source={remote} options={options} />;
|
|
175
201
|
return null;
|
|
176
202
|
}
|
|
177
203
|
|
|
@@ -14,7 +14,7 @@ export function preloadReplayStage(): Promise<unknown> {
|
|
|
14
14
|
/**
|
|
15
15
|
* A headless rrweb player: the recorded page, fitted to its box, with no controls. Drive it
|
|
16
16
|
* through the ref (`play`, `pause`, `seek`, …) and the `onTimeUpdate` / `onPlayingChange`
|
|
17
|
-
* callbacks to build custom player chrome.
|
|
17
|
+
* callbacks to build custom player chrome.
|
|
18
18
|
*/
|
|
19
19
|
export const ReplayStage = forwardRef<ReplayStageHandle, ReplayStageProps>(function ReplayStage(
|
|
20
20
|
{ fallback = null, ...props },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* The headless rrweb stage: mounts rrweb's Replayer, fits the recorded viewport into its box
|
|
2
2
|
and exposes an imperative handle, with no controls of its own. Loaded on demand through
|
|
3
|
-
`ReplayStage
|
|
3
|
+
`ReplayStage`, so rrweb and its stylesheet stay out of the eager graph. */
|
|
4
4
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
|
5
5
|
import type { CSSProperties } from 'react'
|
|
6
6
|
import { Replayer } from 'rrweb'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ReplayEvent } from '../types';
|
|
2
|
+
|
|
3
|
+
/* A small synthetic rrweb recording (58 events, ~9 s, 1280×800) for ReplayPreview's stories, docs and the loop-qa
|
|
4
|
+
block: a shopper on a mock "Northwind" storefront adds two products, opens the cart, types an email and a
|
|
5
|
+
promo code, and "Place order" fails — a custom `network` event (POST /api/checkout 500) and an `error` event
|
|
6
|
+
mark the moment. Recorded with rrweb 2.0.0-alpha.20 against a local page (no external assets), timestamps
|
|
7
|
+
rebased to 2026-09-24 14:32:08 UTC so every render is identical. */
|
|
8
|
+
export const replayDemoEvents: ReplayEvent[] = [
|
|
9
|
+
{"type":4,"data":{"href":"https://shop.northwind.test/collections/trail","width":1280,"height":800},"timestamp":1790260328000},
|
|
10
|
+
{"type":2,"data":{"node":{"type":0,"childNodes":[{"type":1,"name":"html","publicId":"","systemId":"","id":2},{"type":2,"tagName":"html","attributes":{},"childNodes":[{"type":2,"tagName":"head","attributes":{},"childNodes":[{"type":2,"tagName":"meta","attributes":{"charset":"utf-8"},"childNodes":[],"id":5},{"type":2,"tagName":"title","attributes":{},"childNodes":[{"type":3,"textContent":"Northwind Outfitters","id":7}],"id":6},{"type":3,"textContent":"\n","id":8},{"type":2,"tagName":"style","attributes":{"_cssText":"* { box-sizing: border-box; }body { margin: 0px; font: 14px / 1.45 -apple-system, BlinkMacSystemFont, \"Segoe UI\", Inter, sans-serif; color: rgb(28, 25, 23); background: rgb(250, 250, 249); }header { display: flex; align-items: center; gap: 28px; height: 64px; padding: 0px 40px; background: rgb(255, 255, 255); border-bottom: 1px solid rgb(231, 229, 228); }.logo { font-weight: 700; font-size: 17px; letter-spacing: -0.02em; }.logo b { color: rgb(13, 148, 136); }nav a { color: rgb(87, 83, 78); text-decoration: none; margin-right: 20px; }.sp { flex: 1 1 0%; }.cart { position: relative; border: 1px solid rgb(214, 211, 209); background: rgb(255, 255, 255); border-radius: 999px; padding: 7px 14px; font: inherit; cursor: pointer; }.badge { position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; border-radius: 9px; background: rgb(13, 148, 136); color: rgb(255, 255, 255); font-size: 11px; display: grid; place-items: center; padding: 0px 5px; }.hero { padding: 36px 40px 12px; }.hero h1 { margin: 0px; font-size: 30px; letter-spacing: -0.03em; }.hero p { margin: 6px 0px 0px; color: rgb(120, 113, 108); }.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; padding: 20px 40px; }.card { background: rgb(255, 255, 255); border: 1px solid rgb(231, 229, 228); border-radius: 14px; overflow: hidden; transition: box-shadow 0.2s; }.card:hover { box-shadow: rgba(0, 0, 0, 0.08) 0px 8px 24px; }.img { height: 150px; }.i1 { background: linear-gradient(135deg, rgb(153, 246, 228), rgb(13, 148, 136)); }.i2 { background: linear-gradient(135deg, rgb(253, 230, 138), rgb(217, 119, 6)); }.i3 { background: linear-gradient(135deg, rgb(199, 210, 254), rgb(79, 70, 229)); }.i4 { background: linear-gradient(135deg, rgb(254, 205, 211), rgb(225, 29, 72)); }.body { padding: 12px 14px 14px; }.name { font-weight: 600; }.price { color: rgb(120, 113, 108); margin: 2px 0px 10px; }.add { width: 100%; border: 0px; border-radius: 9px; background: rgb(28, 25, 23); color: rgb(255, 255, 255); padding: 9px; font-style: inherit; font-variant: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-language-override: inherit; font-weight: 600; cursor: pointer; }.drawer { position: fixed; top: 0px; right: 0px; bottom: 0px; width: 380px; background: rgb(255, 255, 255); border-left: 1px solid rgb(231, 229, 228); box-shadow: rgba(0, 0, 0, 0.12) -12px 0px 40px; padding: 24px; transform: translateX(100%); transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1); }.drawer.open { transform: none; }.drawer h2 { margin: 0px 0px 16px; font-size: 18px; }.line { display: flex; justify-content: space-between; padding: 10px 0px; border-bottom: 1px solid rgb(245, 245, 244); }label { display: block; font-size: 12px; color: rgb(120, 113, 108); margin: 14px 0px 4px; }input { width: 100%; border: 1px solid rgb(214, 211, 209); border-radius: 9px; padding: 9px 11px; font: inherit; }.pay { margin-top: 18px; width: 100%; border: 0px; border-radius: 10px; background: rgb(13, 148, 136); color: rgb(255, 255, 255); padding: 11px; font-style: inherit; font-variant: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-size-adjust: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-language-override: inherit; font-weight: 600; cursor: pointer; }.err { display: none; margin-top: 14px; border-radius: 10px; background: rgb(254, 242, 242); border: 1px solid rgb(254, 202, 202); color: rgb(185, 28, 28); padding: 10px 12px; font-size: 13px; }.err.show { display: block; }"},"childNodes":[{"type":3,"textContent":"","id":10}],"id":9},{"type":2,"tagName":"script","attributes":{"type":"text/javascript"},"childNodes":[{"type":3,"textContent":"SCRIPT_PLACEHOLDER","id":12}],"id":11}],"id":4},{"type":2,"tagName":"body","attributes":{},"childNodes":[{"type":3,"textContent":"\n","id":14},{"type":2,"tagName":"header","attributes":{},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"logo"},"childNodes":[{"type":3,"textContent":"north","id":17},{"type":2,"tagName":"b","attributes":{},"childNodes":[{"type":3,"textContent":"wind","id":19}],"id":18}],"id":16},{"type":2,"tagName":"nav","attributes":{},"childNodes":[{"type":2,"tagName":"a","attributes":{"href":"file:///tmp/rr/page.html#"},"childNodes":[{"type":3,"textContent":"New","id":22}],"id":21},{"type":2,"tagName":"a","attributes":{"href":"file:///tmp/rr/page.html#"},"childNodes":[{"type":3,"textContent":"Trail","id":24}],"id":23},{"type":2,"tagName":"a","attributes":{"href":"file:///tmp/rr/page.html#"},"childNodes":[{"type":3,"textContent":"Road","id":26}],"id":25},{"type":2,"tagName":"a","attributes":{"href":"file:///tmp/rr/page.html#"},"childNodes":[{"type":3,"textContent":"Sale","id":28}],"id":27}],"id":20},{"type":2,"tagName":"div","attributes":{"class":"sp"},"childNodes":[],"id":29},{"type":2,"tagName":"button","attributes":{"class":"cart","id":"cart"},"childNodes":[{"type":3,"textContent":"Cart ","id":31},{"type":2,"tagName":"span","attributes":{"class":"badge","id":"count"},"childNodes":[{"type":3,"textContent":"0","id":33}],"id":32}],"id":30}],"id":15},{"type":3,"textContent":"\n","id":34},{"type":2,"tagName":"section","attributes":{"class":"hero"},"childNodes":[{"type":2,"tagName":"h1","attributes":{},"childNodes":[{"type":3,"textContent":"Fall trail collection","id":37}],"id":36},{"type":2,"tagName":"p","attributes":{},"childNodes":[{"type":3,"textContent":"Built for mud, rain and long miles.","id":39}],"id":38}],"id":35},{"type":3,"textContent":"\n","id":40},{"type":2,"tagName":"section","attributes":{"class":"grid"},"childNodes":[{"type":3,"textContent":"\n","id":42},{"type":2,"tagName":"div","attributes":{"class":"card"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"img i1"},"childNodes":[],"id":44},{"type":2,"tagName":"div","attributes":{"class":"body"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"name"},"childNodes":[{"type":3,"textContent":"Trail Runner 2","id":47}],"id":46},{"type":2,"tagName":"div","attributes":{"class":"price"},"childNodes":[{"type":3,"textContent":"$148","id":49}],"id":48},{"type":2,"tagName":"button","attributes":{"class":"add","data-p":"Trail Runner 2","data-c":"148"},"childNodes":[{"type":3,"textContent":"Add to cart","id":51}],"id":50}],"id":45}],"id":43},{"type":3,"textContent":"\n","id":52},{"type":2,"tagName":"div","attributes":{"class":"card"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"img i2"},"childNodes":[],"id":54},{"type":2,"tagName":"div","attributes":{"class":"body"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"name"},"childNodes":[{"type":3,"textContent":"Summit Shell","id":57}],"id":56},{"type":2,"tagName":"div","attributes":{"class":"price"},"childNodes":[{"type":3,"textContent":"$229","id":59}],"id":58},{"type":2,"tagName":"button","attributes":{"class":"add","data-p":"Summit Shell","data-c":"229"},"childNodes":[{"type":3,"textContent":"Add to cart","id":61}],"id":60}],"id":55}],"id":53},{"type":3,"textContent":"\n","id":62},{"type":2,"tagName":"div","attributes":{"class":"card"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"img i3"},"childNodes":[],"id":64},{"type":2,"tagName":"div","attributes":{"class":"body"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"name"},"childNodes":[{"type":3,"textContent":"Ridge Pack 28L","id":67}],"id":66},{"type":2,"tagName":"div","attributes":{"class":"price"},"childNodes":[{"type":3,"textContent":"$119","id":69}],"id":68},{"type":2,"tagName":"button","attributes":{"class":"add","data-p":"Ridge Pack 28L","data-c":"119"},"childNodes":[{"type":3,"textContent":"Add to cart","id":71}],"id":70}],"id":65}],"id":63},{"type":3,"textContent":"\n","id":72},{"type":2,"tagName":"div","attributes":{"class":"card"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"img i4"},"childNodes":[],"id":74},{"type":2,"tagName":"div","attributes":{"class":"body"},"childNodes":[{"type":2,"tagName":"div","attributes":{"class":"name"},"childNodes":[{"type":3,"textContent":"Merino Crew","id":77}],"id":76},{"type":2,"tagName":"div","attributes":{"class":"price"},"childNodes":[{"type":3,"textContent":"$68","id":79}],"id":78},{"type":2,"tagName":"button","attributes":{"class":"add","data-p":"Merino Crew","data-c":"68"},"childNodes":[{"type":3,"textContent":"Add to cart","id":81}],"id":80}],"id":75}],"id":73},{"type":3,"textContent":"\n","id":82}],"id":41},{"type":3,"textContent":"\n","id":83},{"type":2,"tagName":"aside","attributes":{"class":"drawer","id":"drawer"},"childNodes":[{"type":2,"tagName":"h2","attributes":{},"childNodes":[{"type":3,"textContent":"Your cart","id":86}],"id":85},{"type":2,"tagName":"div","attributes":{"id":"lines"},"childNodes":[],"id":87},{"type":2,"tagName":"div","attributes":{"class":"line"},"childNodes":[{"type":2,"tagName":"b","attributes":{},"childNodes":[{"type":3,"textContent":"Total","id":90}],"id":89},{"type":2,"tagName":"b","attributes":{"id":"total"},"childNodes":[{"type":3,"textContent":"$0","id":92}],"id":91}],"id":88},{"type":3,"textContent":"\n","id":93},{"type":2,"tagName":"label","attributes":{},"childNodes":[{"type":3,"textContent":"Email","id":95}],"id":94},{"type":2,"tagName":"input","attributes":{"id":"email","placeholder":"you@example.com"},"childNodes":[],"id":96},{"type":2,"tagName":"label","attributes":{},"childNodes":[{"type":3,"textContent":"Promo code","id":98}],"id":97},{"type":2,"tagName":"input","attributes":{"id":"promo","placeholder":"Optional"},"childNodes":[],"id":99},{"type":3,"textContent":"\n","id":100},{"type":2,"tagName":"button","attributes":{"class":"pay","id":"pay"},"childNodes":[{"type":3,"textContent":"Place order","id":102}],"id":101},{"type":2,"tagName":"div","attributes":{"class":"err","id":"err"},"childNodes":[{"type":3,"textContent":"Something went wrong. Please try again.","id":104}],"id":103}],"id":84},{"type":3,"textContent":"\n","id":105},{"type":2,"tagName":"script","attributes":{},"childNodes":[{"type":3,"textContent":"SCRIPT_PLACEHOLDER","id":107}],"id":106},{"type":3,"textContent":"\n","id":108}],"id":13}],"id":3}],"id":1},"initialOffset":{"left":0,"top":0}},"timestamp":1790260328004},
|
|
11
|
+
{"type":3,"data":{"source":1,"positions":[{"x":640,"y":300,"id":41,"timeOffset":0}]},"timestamp":1790260328010},
|
|
12
|
+
{"type":3,"data":{"source":1,"positions":[{"x":608,"y":302,"id":54,"timeOffset":-99},{"x":357,"y":319,"id":54,"timeOffset":-35}]},"timestamp":1790260328511},
|
|
13
|
+
{"type":3,"data":{"source":1,"positions":[{"x":223,"y":330,"id":44,"timeOffset":0}]},"timestamp":1790260329021},
|
|
14
|
+
{"type":3,"data":{"source":1,"positions":[{"x":410,"y":330,"id":54,"timeOffset":-438},{"x":454,"y":341,"id":54,"timeOffset":-109},{"x":247,"y":433,"id":50,"timeOffset":-46}]},"timestamp":1790260329522},
|
|
15
|
+
{"type":3,"data":{"source":2,"type":1,"id":50,"x":182.5,"y":436.5299987792969},"timestamp":1790260329770},
|
|
16
|
+
{"type":3,"data":{"source":2,"type":5,"id":50},"timestamp":1790260329770},
|
|
17
|
+
{"type":3,"data":{"source":2,"type":0,"id":50,"x":182.5,"y":436.5299987792969},"timestamp":1790260329770},
|
|
18
|
+
{"type":3,"data":{"source":2,"type":2,"id":50,"x":182,"y":436,"pointerType":0},"timestamp":1790260329770},
|
|
19
|
+
{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[{"parentId":32,"id":33},{"parentId":91,"id":92}],"adds":[{"parentId":32,"nextId":null,"node":{"type":3,"textContent":"1","id":109}},{"parentId":87,"nextId":null,"node":{"type":2,"tagName":"div","attributes":{"class":"line"},"childNodes":[],"id":110}},{"parentId":110,"nextId":null,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":111}},{"parentId":111,"nextId":null,"node":{"type":3,"textContent":"$148","id":112}},{"parentId":91,"nextId":null,"node":{"type":3,"textContent":"$148","id":113}},{"parentId":110,"nextId":111,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":114}},{"parentId":114,"nextId":null,"node":{"type":3,"textContent":"Trail Runner 2","id":115}}]},"timestamp":1790260329771},
|
|
20
|
+
{"type":3,"data":{"source":1,"positions":[{"x":182,"y":436,"id":50,"timeOffset":-253}]},"timestamp":1790260330023},
|
|
21
|
+
{"type":5,"data":{"tag":"checkpoint","payload":{"label":"Added Trail Runner 2"}},"timestamp":1790260330279},
|
|
22
|
+
{"type":3,"data":{"source":1,"positions":[{"x":223,"y":438,"id":50,"timeOffset":-243},{"x":512,"y":454,"id":60,"timeOffset":-181}]},"timestamp":1790260330524},
|
|
23
|
+
{"type":3,"data":{"source":2,"type":1,"id":70,"x":792.5,"y":436.5299987792969},"timestamp":1790260330663},
|
|
24
|
+
{"type":3,"data":{"source":2,"type":6,"id":50},"timestamp":1790260330663},
|
|
25
|
+
{"type":3,"data":{"source":2,"type":5,"id":70},"timestamp":1790260330663},
|
|
26
|
+
{"type":3,"data":{"source":2,"type":0,"id":70,"x":792.5,"y":436.5299987792969},"timestamp":1790260330663},
|
|
27
|
+
{"type":3,"data":{"source":2,"type":2,"id":70,"x":792,"y":436,"pointerType":0},"timestamp":1790260330663},
|
|
28
|
+
{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[{"parentId":32,"id":109},{"parentId":87,"id":110},{"parentId":91,"id":113}],"adds":[{"parentId":32,"nextId":null,"node":{"type":3,"textContent":"2","id":116}},{"parentId":87,"nextId":null,"node":{"type":2,"tagName":"div","attributes":{"class":"line"},"childNodes":[],"id":117}},{"parentId":117,"nextId":null,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":118}},{"parentId":118,"nextId":null,"node":{"type":3,"textContent":"$119","id":119}},{"parentId":91,"nextId":null,"node":{"type":3,"textContent":"$267","id":120}},{"parentId":87,"nextId":117,"node":{"type":2,"tagName":"div","attributes":{"class":"line"},"childNodes":[],"id":121}},{"parentId":121,"nextId":null,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":122}},{"parentId":121,"nextId":122,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":123}},{"parentId":123,"nextId":null,"node":{"type":3,"textContent":"Trail Runner 2","id":124}},{"parentId":122,"nextId":null,"node":{"type":3,"textContent":"$148","id":125}},{"parentId":117,"nextId":118,"node":{"type":2,"tagName":"span","attributes":{},"childNodes":[],"id":126}},{"parentId":126,"nextId":null,"node":{"type":3,"textContent":"Ridge Pack 28L","id":127}}]},"timestamp":1790260330664},
|
|
29
|
+
{"type":3,"data":{"source":1,"positions":[{"x":792,"y":436,"id":70,"timeOffset":-363}]},"timestamp":1790260331025},
|
|
30
|
+
{"type":3,"data":{"source":1,"positions":[{"x":815,"y":414,"id":65,"timeOffset":-249},{"x":1003,"y":234,"id":74,"timeOffset":-183},{"x":1191,"y":54,"id":15,"timeOffset":-116}]},"timestamp":1790260331526},
|
|
31
|
+
{"type":3,"data":{"source":2,"type":1,"id":30,"x":1211.1400146484375,"y":31.489999771118164},"timestamp":1790260331688},
|
|
32
|
+
{"type":3,"data":{"source":2,"type":6,"id":70},"timestamp":1790260331688},
|
|
33
|
+
{"type":3,"data":{"source":2,"type":5,"id":30},"timestamp":1790260331688},
|
|
34
|
+
{"type":3,"data":{"source":2,"type":0,"id":30,"x":1211.1400146484375,"y":31.489999771118164},"timestamp":1790260331688},
|
|
35
|
+
{"type":3,"data":{"source":2,"type":2,"id":30,"x":1211,"y":31,"pointerType":0},"timestamp":1790260331688},
|
|
36
|
+
{"type":3,"data":{"source":0,"texts":[],"attributes":[{"id":84,"attributes":{"class":"drawer open"}}],"removes":[],"adds":[]},"timestamp":1790260331688},
|
|
37
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1211,"y":31,"id":30,"timeOffset":-339}]},"timestamp":1790260332028},
|
|
38
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1200,"y":53,"id":84,"timeOffset":-137},{"x":1112,"y":225,"id":96,"timeOffset":-68}]},"timestamp":1790260332529},
|
|
39
|
+
{"type":3,"data":{"source":2,"type":1,"id":96,"x":1090.5,"y":245.52000427246094},"timestamp":1790260332705},
|
|
40
|
+
{"type":3,"data":{"source":2,"type":6,"id":30},"timestamp":1790260332705},
|
|
41
|
+
{"type":3,"data":{"source":2,"type":5,"id":96},"timestamp":1790260332705},
|
|
42
|
+
{"type":3,"data":{"source":2,"type":0,"id":96,"x":1090.5,"y":245.52000427246094},"timestamp":1790260332705},
|
|
43
|
+
{"type":3,"data":{"source":2,"type":2,"id":96,"x":1090,"y":245,"pointerType":0},"timestamp":1790260332705},
|
|
44
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1090,"y":245,"id":96,"timeOffset":-325}]},"timestamp":1790260333030},
|
|
45
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1088,"y":263,"id":96,"timeOffset":0}]},"timestamp":1790260333853},
|
|
46
|
+
{"type":3,"data":{"source":2,"type":1,"id":99,"x":1090.5,"y":321.2099914550781},"timestamp":1790260333913},
|
|
47
|
+
{"type":3,"data":{"source":5,"text":"maya@northwind.test","isChecked":false,"id":96},"timestamp":1790260333913},
|
|
48
|
+
{"type":3,"data":{"source":2,"type":6,"id":96},"timestamp":1790260333913},
|
|
49
|
+
{"type":3,"data":{"source":2,"type":5,"id":99},"timestamp":1790260333913},
|
|
50
|
+
{"type":3,"data":{"source":2,"type":0,"id":99,"x":1090.5,"y":321.2099914550781},"timestamp":1790260333914},
|
|
51
|
+
{"type":3,"data":{"source":2,"type":2,"id":99,"x":1090,"y":321,"pointerType":0},"timestamp":1790260333914},
|
|
52
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1090,"y":321,"id":99,"timeOffset":-441}]},"timestamp":1790260334354},
|
|
53
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1090,"y":330,"id":99,"timeOffset":-193},{"x":1090,"y":401,"id":101,"timeOffset":-128}]},"timestamp":1790260334855},
|
|
54
|
+
{"type":3,"data":{"source":2,"type":1,"id":101,"x":1090.5,"y":380.5},"timestamp":1790260334954},
|
|
55
|
+
{"type":3,"data":{"source":5,"text":"FALL25","isChecked":false,"id":99},"timestamp":1790260334954},
|
|
56
|
+
{"type":3,"data":{"source":2,"type":6,"id":99},"timestamp":1790260334954},
|
|
57
|
+
{"type":3,"data":{"source":2,"type":5,"id":101},"timestamp":1790260334954},
|
|
58
|
+
{"type":3,"data":{"source":2,"type":0,"id":101,"x":1090.5,"y":380.5},"timestamp":1790260334954},
|
|
59
|
+
{"type":3,"data":{"source":2,"type":2,"id":101,"x":1090,"y":380,"pointerType":0},"timestamp":1790260334954},
|
|
60
|
+
{"type":3,"data":{"source":0,"texts":[],"attributes":[],"removes":[{"parentId":101,"id":102}],"adds":[{"parentId":101,"nextId":null,"node":{"type":3,"textContent":"Placing order…","id":128}}]},"timestamp":1790260334954},
|
|
61
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1090,"y":380,"id":101,"timeOffset":-402}]},"timestamp":1790260335356},
|
|
62
|
+
{"type":5,"data":{"tag":"network","payload":{"method":"POST","status":500,"url":"/api/checkout","label":"POST /api/checkout 500"}},"timestamp":1790260335855},
|
|
63
|
+
{"type":5,"data":{"tag":"error","payload":{"label":"TypeError","message":"Cannot read properties of undefined (reading 'total') at applyPromo (checkout.ts:88)"}},"timestamp":1790260335856},
|
|
64
|
+
{"type":3,"data":{"source":0,"texts":[],"attributes":[{"id":103,"attributes":{"class":"err show"}}],"removes":[{"parentId":101,"id":128}],"adds":[{"parentId":101,"nextId":null,"node":{"type":3,"textContent":"Place order","id":129}}]},"timestamp":1790260335856},
|
|
65
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1085,"y":388,"id":101,"timeOffset":0}]},"timestamp":1790260336357},
|
|
66
|
+
{"type":3,"data":{"source":1,"positions":[{"x":1050,"y":444,"id":103,"timeOffset":-441}]},"timestamp":1790260336859},
|
|
67
|
+
];
|
package/src/replay/index.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
export { ReplayEmbed, ReplayPreview } from './ReplayPreview';
|
|
1
|
+
export { ReplayEmbed, ReplayPreview, formatReplayTime } from './ReplayPreview';
|
|
2
2
|
export type {
|
|
3
|
+
ReplayChrome,
|
|
3
4
|
ReplayEventsSource,
|
|
4
5
|
ReplayEventsUrlSource,
|
|
5
6
|
ReplayPageSource,
|
|
7
|
+
ReplayPlayerOptions,
|
|
8
|
+
ReplayPreviewEventsProps,
|
|
9
|
+
ReplayPreviewHandle,
|
|
6
10
|
ReplayPreviewProps,
|
|
11
|
+
ReplayPreviewSourceProps,
|
|
7
12
|
ReplaySource,
|
|
8
13
|
} from './ReplayPreview';
|
|
9
14
|
export { ReplayStage, preloadReplayStage } from './ReplayStage';
|
package/src/replay/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* rrweb's event shape and the numeric enums the replay helpers read, declared locally so the
|
|
2
|
-
eager replay modules (and their published declarations) never import rrweb. rrweb is
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
eager replay modules (and their published declarations) never import rrweb. rrweb is
|
|
3
|
+
lazy: only the player chunk (`ReplayStageImpl`) imports it, so pages that
|
|
4
|
+
never play native events never download it. */
|
|
5
5
|
|
|
6
6
|
/** One recorded rrweb event. rrweb's own `eventWithTime` is assignable to it. */
|
|
7
7
|
export interface ReplayEvent {
|