@reactra/replay-devtools 0.1.0-alpha.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.
@@ -0,0 +1,101 @@
1
+ import type { ReplayEvent, SessionBundle } from "@reactra/behaviours/replayable";
2
+ import { diffKeys } from "@reactra/replay";
3
+ import type { ReplayPlayer } from "@reactra/replay";
4
+ export { diffKeys };
5
+ /** Visual identity of one event type on the timeline + table. */
6
+ export interface EventStyle {
7
+ /** CSS color for the timeline tick / table chip. */
8
+ color: string;
9
+ /** Single-character glyph for compact rows. */
10
+ glyph: string;
11
+ }
12
+ export declare const eventStyle: (e: ReplayEvent) => EventStyle;
13
+ /** One-line human summary of a recorded event (table detail column). */
14
+ export declare const describeEvent: (e: ReplayEvent) => string;
15
+ /** "+12.3s" — timeline offset formatting. */
16
+ export declare const formatOffset: (ms: number) => string;
17
+ /**
18
+ * The sessions-list query string for a "key=value" filter-box value —
19
+ * `?meta.<key>=<value>` (the replay-server read API; NOT a Reactra spec
20
+ * contract). Whitespace-trimmed; no "=" or empty key/value → "".
21
+ */
22
+ export declare const sessionsQuery: (metaFilter: string) => string;
23
+ /** Bearer-or-custom auth headers for the read API fetches. */
24
+ export declare const authHeaders: (token?: string, headers?: () => HeadersInit) => HeadersInit;
25
+ /**
26
+ * Sorted unique event offsets — the timeline's discrete stops. With a
27
+ * `predicate`, only matching events contribute stops: the transport
28
+ * (prev/next/playback/drive) then walks ONLY the filtered events — the
29
+ * type/instance chips and the from/to window all funnel through here.
30
+ */
31
+ export declare const eventStops: (bundle: SessionBundle, predicate?: (e: ReplayEvent) => boolean) => number[];
32
+ /**
33
+ * Clamp one dragged edge of the timeline window (the Chrome-Network-style
34
+ * brush). The dragged edge stays inside [0, duration] and never crosses the
35
+ * opposite edge.
36
+ */
37
+ export declare const clampWindowEdge: (edge: "from" | "to", value: number, other: number, duration: number) => number;
38
+ /** The index of the latest stop ≤ `offset` (-1 = before all stops). */
39
+ export declare const stopIndexAt: (stops: readonly number[], offset: number) => number;
40
+ /** Recorded instance ids in first-seen order (filter chips + state cards). */
41
+ export declare const instanceIds: (bundle: SessionBundle) => string[];
42
+ /**
43
+ * Playback delay until the next stop, at `speed`× real time. The gap is floored
44
+ * at MIN_STEP_MS so clustered/same-timestamp events remain visible, then divided
45
+ * by `speed`; long recorded idles are clamped so auto-play never stalls the
46
+ * viewer (max 2s wall time).
47
+ */
48
+ export declare const playbackDelay: (curOffset: number, nextOffset: number, speed: number) => number;
49
+ /**
50
+ * Gridline offsets for the timeline's time scale: the smallest "nice" step
51
+ * (100ms / 250ms / … / 1h) that yields at most `targetCount` ticks across
52
+ * `durationMs`, starting at 0. A zero/negative duration has just the origin.
53
+ */
54
+ export declare const timeScaleTicks: (durationMs: number, targetCount?: number) => number[];
55
+ /**
56
+ * Route-first drive decision (Replay §5 C2): given the route `path` folded at
57
+ * the scrub target and the current browser location, return the path to
58
+ * `navigate()` to — or `undefined` when no navigation is needed (no recorded
59
+ * route, or the URL already matches). Navigating only on a real difference
60
+ * keeps scrub idempotent and avoids spurious history churn.
61
+ */
62
+ export declare const routeDriveTarget: (recordedPath: string | undefined, currentLocation: string) => string | undefined;
63
+ /**
64
+ * A filesystem-safe download filename for a `SessionBundle`.
65
+ *
66
+ * Format: `replay-<sessionId>-<YYYY-MM-DD>.json`. All characters are safe
67
+ * for every major OS file system — no spaces, slashes, colons, or other
68
+ * characters that require escaping in a `Content-Disposition` header or a
69
+ * `<a download>` attribute.
70
+ */
71
+ export declare const bundleFilename: (b: SessionBundle) => string;
72
+ /**
73
+ * Serialize a `SessionBundle` to a JSON string that round-trips without loss.
74
+ *
75
+ * The output is the wire format — importing and exporting a bundle should
76
+ * produce a byte-identical file (modulo key ordering, which `JSON.parse` then
77
+ * `JSON.stringify` may alter, but the data is structurally equal).
78
+ */
79
+ export declare const bundleToBlobText: (b: SessionBundle) => string;
80
+ /**
81
+ * Walk `stops` from `fromIndex + dir` (direction `dir`: 1=forward, -1=backward)
82
+ * and return the index of the first stop where `key` changes for instance `id`.
83
+ *
84
+ * "Changes" means the key is in `diffKeys(stateAt(j-1), stateAt(j))` — the
85
+ * same shallow-JSON comparison the state-card highlights use. When walking
86
+ * backward the comparison is reversed: the "previous" is `stops[j]` and the
87
+ * "current" for the diff is the stop that was displayed at the cursor
88
+ * (i.e. `stops[j+1]`), so clicking "previous change" lands on the stop that
89
+ * INTRODUCED the value the cursor is showing.
90
+ *
91
+ * Returns `null` when no such stop exists (reached end of range, or `id`/`key`
92
+ * absent throughout). Pure — no panel state touched; safe to call in a handler.
93
+ *
94
+ * Per-stop cost is one `statesAt` call (O(n) over snapshots). The walk is
95
+ * bounded by the filtered `stops` length, which is the set the panel already
96
+ * renders.
97
+ */
98
+ export declare const nextChangeStop: (player: ReplayPlayer, bundle: SessionBundle, stops: readonly number[], fromIndex: number, id: string, key: string, dir: 1 | -1) => number | null;
99
+ /** Compact scale-tick label: "0s", "12s", "1.5s", "2m", "2m30s". */
100
+ export declare const formatScaleTick: (ms: number) => string;
101
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAInD,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;IACb,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAA;CACd;AAMD,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,KAAG,UAsB3C,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,aAAa,GAAI,GAAG,WAAW,KAAG,MAe9C,CAAA;AAED,6CAA6C;AAC7C,eAAO,MAAM,YAAY,GAAI,IAAI,MAAM,KAAG,MAAuC,CAAA;AAEjF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,MAAM,KAAG,MAOlD,CAAA;AAED,8DAA8D;AAC9D,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,UAAU,MAAM,WAAW,KAC1B,WAIF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,aAAa,EACrB,YAAY,CAAC,CAAC,EAAE,WAAW,KAAK,OAAO,KACtC,MAAM,EAKgB,CAAA;AAEzB;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,GAAG,IAAI,EACnB,OAAO,MAAM,EACb,OAAO,MAAM,EACb,UAAU,MAAM,KACf,MAGF,CAAA;AAED,uEAAuE;AACvE,eAAO,MAAM,WAAW,GAAI,OAAO,SAAS,MAAM,EAAE,EAAE,QAAQ,MAAM,KAAG,MAOtE,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,WAAW,GAAI,QAAQ,aAAa,KAAG,MAAM,EAMzD,CAAA;AAWD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,EAAE,YAAY,MAAM,EAAE,OAAO,MAAM,KAAG,MACd,CAAA;AAQvE;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,EAAE,oBAAe,KAAG,MAAM,EAO1E,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,GAAG,SAAS,EAChC,iBAAiB,MAAM,KACtB,MAAM,GAAG,SAGX,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,GAAG,aAAa,KAAG,MAIjD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,aAAa,KAAG,MAA2B,CAAA;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,GACzB,QAAQ,YAAY,EACpB,QAAQ,aAAa,EACrB,OAAO,SAAS,MAAM,EAAE,EACxB,WAAW,MAAM,EACjB,IAAI,MAAM,EACV,KAAK,MAAM,EACX,KAAK,CAAC,GAAG,CAAC,CAAC,KACV,MAAM,GAAG,IAwBX,CAAA;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,MAO5C,CAAA"}
@@ -0,0 +1,236 @@
1
+ // @reactra/replay-devtools — pure panel logic (no React, no DOM).
2
+ //
3
+ // Owner: reactra-runtime-spec.md §3 (`@reactra/replay-devtools`, internal
4
+ // tier — exported for tests); the event/bundle shapes are Replay spec §3.
5
+ // Everything here is Node-portable by construction so the panel's behaviour
6
+ // is unit-testable without a renderer.
7
+ import { diffKeys } from "@reactra/replay";
8
+ // COND-2: diffKeys is now defined in @reactra/replay; re-exported here so all
9
+ // existing import paths (replay-devtools consumers + the /timeline subpath) keep
10
+ // working unchanged.
11
+ export { diffKeys };
12
+ // Timeline color language: one hue per concern, keyframes emphasized. The colors
13
+ // are `--rdt-ev-*` TOKENS (not literal hex) so they stay visible on BOTH the dark
14
+ // and light track/table backgrounds — a single fixed hue (especially the
15
+ // near-white keyframe marker) is invisible on a light background. Owner: /tokens.
16
+ export const eventStyle = (e) => {
17
+ switch (e.type) {
18
+ case "action":
19
+ return { color: "var(--rdt-ev-action)", glyph: "▶" };
20
+ case "state_snapshot":
21
+ return e.keyframe
22
+ ? { color: "var(--rdt-ev-keyframe)", glyph: "⬛" }
23
+ : { color: "var(--rdt-ev-delta)", glyph: "Δ" };
24
+ case "resource":
25
+ return { color: "var(--rdt-ev-resource)", glyph: "◆" };
26
+ case "mount":
27
+ return e.phase === "mount"
28
+ ? { color: "var(--rdt-ev-mount)", glyph: "+" }
29
+ : { color: "var(--rdt-ev-unmount)", glyph: "−" };
30
+ case "gap":
31
+ return { color: "var(--rdt-ev-gap)", glyph: "⚠" };
32
+ case "tx_mark":
33
+ return {
34
+ color: "var(--rdt-ev-action)",
35
+ glyph: e.phase === "optimistic" ? "⚡" : e.phase === "rolledback" ? "↩" : "✓",
36
+ };
37
+ }
38
+ };
39
+ /** One-line human summary of a recorded event (table detail column). */
40
+ export const describeEvent = (e) => {
41
+ switch (e.type) {
42
+ case "mount":
43
+ return e.phase;
44
+ case "action":
45
+ return `${e.name}(${e.payload.map((p) => JSON.stringify(p)).join(", ")}) — ${e.duration.toFixed(1)}ms`;
46
+ case "state_snapshot":
47
+ return `${e.keyframe ? "keyframe " : ""}${JSON.stringify(e.state)}`;
48
+ case "resource":
49
+ return `${e.name} → ${e.status}`;
50
+ case "gap":
51
+ return `${e.dropped} events dropped (rate guard)`;
52
+ case "tx_mark":
53
+ return `command ${e.phase}: ${JSON.stringify(e.state)}`;
54
+ }
55
+ };
56
+ /** "+12.3s" — timeline offset formatting. */
57
+ export const formatOffset = (ms) => `+${(ms / 1000).toFixed(1)}s`;
58
+ /**
59
+ * The sessions-list query string for a "key=value" filter-box value —
60
+ * `?meta.<key>=<value>` (the replay-server read API; NOT a Reactra spec
61
+ * contract). Whitespace-trimmed; no "=" or empty key/value → "".
62
+ */
63
+ export const sessionsQuery = (metaFilter) => {
64
+ const eq = metaFilter.indexOf("=");
65
+ if (eq <= 0)
66
+ return "";
67
+ const key = metaFilter.slice(0, eq).trim();
68
+ const value = metaFilter.slice(eq + 1).trim();
69
+ if (!key || !value)
70
+ return "";
71
+ return `?meta.${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
72
+ };
73
+ /** Bearer-or-custom auth headers for the read API fetches. */
74
+ export const authHeaders = (token, headers) => {
75
+ if (headers)
76
+ return headers();
77
+ if (token)
78
+ return { authorization: `Bearer ${token}` };
79
+ return {};
80
+ };
81
+ /**
82
+ * Sorted unique event offsets — the timeline's discrete stops. With a
83
+ * `predicate`, only matching events contribute stops: the transport
84
+ * (prev/next/playback/drive) then walks ONLY the filtered events — the
85
+ * type/instance chips and the from/to window all funnel through here.
86
+ */
87
+ export const eventStops = (bundle, predicate) => [
88
+ ...new Set(bundle.events.filter((e) => !predicate || predicate(e)).map((e) => e.timestamp - bundle.startTime)),
89
+ ].sort((a, b) => a - b);
90
+ /**
91
+ * Clamp one dragged edge of the timeline window (the Chrome-Network-style
92
+ * brush). The dragged edge stays inside [0, duration] and never crosses the
93
+ * opposite edge.
94
+ */
95
+ export const clampWindowEdge = (edge, value, other, duration) => {
96
+ const v = Math.min(duration, Math.max(0, value));
97
+ return edge === "from" ? Math.min(v, other) : Math.max(v, other);
98
+ };
99
+ /** The index of the latest stop ≤ `offset` (-1 = before all stops). */
100
+ export const stopIndexAt = (stops, offset) => {
101
+ let i = -1;
102
+ for (const t of stops) {
103
+ if (t <= offset)
104
+ i++;
105
+ else
106
+ break;
107
+ }
108
+ return i;
109
+ };
110
+ /** Recorded instance ids in first-seen order (filter chips + state cards). */
111
+ export const instanceIds = (bundle) => {
112
+ const seen = [];
113
+ for (const e of bundle.events) {
114
+ if (!seen.includes(e.componentId))
115
+ seen.push(e.componentId);
116
+ }
117
+ return seen;
118
+ };
119
+ /**
120
+ * The minimum per-step gap (ms) auto-play honours before dividing by `speed`.
121
+ * Recorded commits often cluster within a few ms of each other (React commits
122
+ * in bursts), so a raw 16ms floor flashed the whole flow past in one frame and
123
+ * read as "nothing played". 200ms makes each step perceptible at 1× while
124
+ * higher speeds still accelerate it (e.g. 4× → 50ms/step).
125
+ */
126
+ const MIN_STEP_MS = 200;
127
+ /**
128
+ * Playback delay until the next stop, at `speed`× real time. The gap is floored
129
+ * at MIN_STEP_MS so clustered/same-timestamp events remain visible, then divided
130
+ * by `speed`; long recorded idles are clamped so auto-play never stalls the
131
+ * viewer (max 2s wall time).
132
+ */
133
+ export const playbackDelay = (curOffset, nextOffset, speed) => Math.min(2000, Math.max(MIN_STEP_MS, nextOffset - curOffset) / speed);
134
+ /** The "nice" step candidates for the timeline's time scale, in ms. */
135
+ const SCALE_STEPS = [
136
+ 100, 250, 500, 1_000, 2_000, 5_000, 10_000, 15_000, 30_000,
137
+ 60_000, 120_000, 300_000, 600_000, 1_800_000, 3_600_000,
138
+ ];
139
+ /**
140
+ * Gridline offsets for the timeline's time scale: the smallest "nice" step
141
+ * (100ms / 250ms / … / 1h) that yields at most `targetCount` ticks across
142
+ * `durationMs`, starting at 0. A zero/negative duration has just the origin.
143
+ */
144
+ export const timeScaleTicks = (durationMs, targetCount = 8) => {
145
+ if (durationMs <= 0)
146
+ return [0];
147
+ const step = SCALE_STEPS.find((s) => durationMs / s <= targetCount) ?? SCALE_STEPS[SCALE_STEPS.length - 1];
148
+ const ticks = [];
149
+ for (let t = 0; t <= durationMs; t += step)
150
+ ticks.push(t);
151
+ return ticks;
152
+ };
153
+ /**
154
+ * Route-first drive decision (Replay §5 C2): given the route `path` folded at
155
+ * the scrub target and the current browser location, return the path to
156
+ * `navigate()` to — or `undefined` when no navigation is needed (no recorded
157
+ * route, or the URL already matches). Navigating only on a real difference
158
+ * keeps scrub idempotent and avoids spurious history churn.
159
+ */
160
+ export const routeDriveTarget = (recordedPath, currentLocation) => {
161
+ if (recordedPath === undefined)
162
+ return undefined;
163
+ return recordedPath === currentLocation ? undefined : recordedPath;
164
+ };
165
+ /**
166
+ * A filesystem-safe download filename for a `SessionBundle`.
167
+ *
168
+ * Format: `replay-<sessionId>-<YYYY-MM-DD>.json`. All characters are safe
169
+ * for every major OS file system — no spaces, slashes, colons, or other
170
+ * characters that require escaping in a `Content-Disposition` header or a
171
+ * `<a download>` attribute.
172
+ */
173
+ export const bundleFilename = (b) => {
174
+ const d = new Date(b.startTime);
175
+ const ymd = `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`;
176
+ return `replay-${b.sessionId}-${ymd}.json`;
177
+ };
178
+ /**
179
+ * Serialize a `SessionBundle` to a JSON string that round-trips without loss.
180
+ *
181
+ * The output is the wire format — importing and exporting a bundle should
182
+ * produce a byte-identical file (modulo key ordering, which `JSON.parse` then
183
+ * `JSON.stringify` may alter, but the data is structurally equal).
184
+ */
185
+ export const bundleToBlobText = (b) => JSON.stringify(b);
186
+ /**
187
+ * Walk `stops` from `fromIndex + dir` (direction `dir`: 1=forward, -1=backward)
188
+ * and return the index of the first stop where `key` changes for instance `id`.
189
+ *
190
+ * "Changes" means the key is in `diffKeys(stateAt(j-1), stateAt(j))` — the
191
+ * same shallow-JSON comparison the state-card highlights use. When walking
192
+ * backward the comparison is reversed: the "previous" is `stops[j]` and the
193
+ * "current" for the diff is the stop that was displayed at the cursor
194
+ * (i.e. `stops[j+1]`), so clicking "previous change" lands on the stop that
195
+ * INTRODUCED the value the cursor is showing.
196
+ *
197
+ * Returns `null` when no such stop exists (reached end of range, or `id`/`key`
198
+ * absent throughout). Pure — no panel state touched; safe to call in a handler.
199
+ *
200
+ * Per-stop cost is one `statesAt` call (O(n) over snapshots). The walk is
201
+ * bounded by the filtered `stops` length, which is the set the panel already
202
+ * renders.
203
+ */
204
+ export const nextChangeStop = (player, bundle, stops, fromIndex, id, key, dir) => {
205
+ const start = fromIndex + dir;
206
+ const end = dir === 1 ? stops.length - 1 : 0;
207
+ for (let j = start; dir === 1 ? j <= end : j >= end; j += dir) {
208
+ const curStop = stops[j];
209
+ if (curStop === undefined)
210
+ break;
211
+ const curState = player.statesAt(bundle.startTime + curStop).get(id);
212
+ if (!curState || !(key in curState))
213
+ continue;
214
+ // A stop "changes" `key` when diffKeys(state@(j-1), state@j) includes it.
215
+ // This is the same comparison in both directions — walking backward just
216
+ // means we visit the stops in reverse order to find the most-recent prior
217
+ // change point.
218
+ const prevStop = stops[j - 1];
219
+ const prevState = prevStop !== undefined
220
+ ? player.statesAt(bundle.startTime + prevStop).get(id)
221
+ : undefined;
222
+ if (diffKeys(prevState, curState).includes(key))
223
+ return j;
224
+ }
225
+ return null;
226
+ };
227
+ /** Compact scale-tick label: "0s", "12s", "1.5s", "2m", "2m30s". */
228
+ export const formatScaleTick = (ms) => {
229
+ if (ms >= 60_000) {
230
+ const m = Math.floor(ms / 60_000);
231
+ const s = Math.round((ms % 60_000) / 1000);
232
+ return s === 0 ? `${m}m` : `${m}m${s}s`;
233
+ }
234
+ return `${Number((ms / 1000).toFixed(2))}s`;
235
+ };
236
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { ReplayDevtools, type ReplayDevtoolsProps } from "./panel.ts";
2
+ export { authHeaders as __authHeaders, bundleFilename as __bundleFilename, bundleToBlobText as __bundleToBlobText, describeEvent as __describeEvent, diffKeys as __diffKeys, eventStops as __eventStops, eventStyle as __eventStyle, formatOffset as __formatOffset, instanceIds as __instanceIds, playbackDelay as __playbackDelay, sessionsQuery as __sessionsQuery, stopIndexAt as __stopIndexAt, } from "./helpers.ts";
3
+ export { __resetStylesForTest, ensureStyles as __ensureStyles } from "./styles.ts";
4
+ export { __resetTokensForTest } from "./tokens.ts";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGrE,OAAO,EACL,WAAW,IAAI,aAAa,EAC5B,cAAc,IAAI,gBAAgB,EAClC,gBAAgB,IAAI,kBAAkB,EACtC,aAAa,IAAI,eAAe,EAChC,QAAQ,IAAI,UAAU,EACtB,UAAU,IAAI,YAAY,EAC1B,UAAU,IAAI,YAAY,EAC1B,YAAY,IAAI,cAAc,EAC9B,WAAW,IAAI,aAAa,EAC5B,aAAa,IAAI,eAAe,EAChC,aAAa,IAAI,eAAe,EAChC,WAAW,IAAI,aAAa,GAC7B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,oBAAoB,EAAE,YAAY,IAAI,cAAc,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // @reactra/replay-devtools — public surface.
2
+ //
3
+ // Owner: reactra-runtime-spec.md §2 (UI-companion tier) + §3. User-facing:
4
+ // the panel and its props type. The pure helpers are internal tier —
5
+ // re-exported __-prefixed for tests only, never documented as user API.
6
+ //
7
+ // The `/chrome` and `/tokens` subpaths are separate named exports (not
8
+ // re-exported here) — consumers import from `@reactra/replay-devtools/chrome`
9
+ // and `@reactra/replay-devtools/tokens` directly (package.json exports map).
10
+ export { ReplayDevtools } from "./panel.js";
11
+ // Internal tier (tests only — Runtime spec §1 visibility tiers).
12
+ export { authHeaders as __authHeaders, bundleFilename as __bundleFilename, bundleToBlobText as __bundleToBlobText, describeEvent as __describeEvent, diffKeys as __diffKeys, eventStops as __eventStops, eventStyle as __eventStyle, formatOffset as __formatOffset, instanceIds as __instanceIds, playbackDelay as __playbackDelay, sessionsQuery as __sessionsQuery, stopIndexAt as __stopIndexAt, } from "./helpers.js";
13
+ export { __resetStylesForTest, ensureStyles as __ensureStyles } from "./styles.js";
14
+ export { __resetTokensForTest } from "./tokens.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,2EAA2E;AAC3E,qEAAqE;AACrE,wEAAwE;AACxE,EAAE;AACF,uEAAuE;AACvE,8EAA8E;AAC9E,6EAA6E;AAE7E,OAAO,EAAE,cAAc,EAA4B,MAAM,YAAY,CAAA;AAErE,iEAAiE;AACjE,OAAO,EACL,WAAW,IAAI,aAAa,EAC5B,cAAc,IAAI,gBAAgB,EAClC,gBAAgB,IAAI,kBAAkB,EACtC,aAAa,IAAI,eAAe,EAChC,QAAQ,IAAI,UAAU,EACtB,UAAU,IAAI,YAAY,EAC1B,UAAU,IAAI,YAAY,EAC1B,YAAY,IAAI,cAAc,EAC9B,WAAW,IAAI,aAAa,EAC5B,aAAa,IAAI,eAAe,EAChC,aAAa,IAAI,eAAe,EAChC,WAAW,IAAI,aAAa,GAC7B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,oBAAoB,EAAE,YAAY,IAAI,cAAc,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { type ReactNode } from "react";
2
+ /** Props of the session-recorder panel (Runtime spec §3). */
3
+ export interface ReplayDevtoolsProps {
4
+ /** Base path of the replay-server HTTP READ API (default `"/replay"`). */
5
+ endpoint?: string;
6
+ /** Bearer-token sugar for the read API (REPLAY_TOKEN deployments). */
7
+ token?: string;
8
+ /** Custom auth-header supplier — wins over `token`. */
9
+ headers?: () => HeadersInit;
10
+ /** Start with the drawer open instead of the collapsed pill. */
11
+ defaultOpen?: boolean;
12
+ /** Show the live re-drive toggle (default true). */
13
+ drive?: boolean;
14
+ }
15
+ /**
16
+ * The Reactra session-recorder panel: finalize-and-scrub, a color-coded
17
+ * visual timeline, transport controls with auto-playback, keyboard stepping
18
+ * (←/→/space), per-instance state cards with change highlighting, event-type
19
+ * and instance filters, live re-drive, and server-session browsing.
20
+ *
21
+ * Window chrome: Shift+Alt+R hotkey, drag-to-resize, minimize, pop-out,
22
+ * System→Light→Dark theme — all powered by the shared `/chrome` helpers.
23
+ */
24
+ export declare const ReplayDevtools: (props: ReplayDevtoolsProps) => ReactNode;
25
+ //# sourceMappingURL=panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../src/panel.ts"],"names":[],"mappings":"AA2BA,OAAO,EAA4D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAiChG,6DAA6D;AAC7D,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,WAAW,CAAA;IAC3B,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAaD;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,mBAAmB,KAAG,SAq3B3D,CAAA"}