issue-sticker 0.8.1 → 0.9.1
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/CHANGELOG.md +38 -0
- package/README.md +33 -0
- package/dist/{externalUserPayload-D-P1-QaW.js → externalUserPayload-CVYSPfcx.js} +1778 -737
- package/dist/issue-sticker-headless-react.js +175 -33
- package/dist/issue-sticker-headless.js +38 -10
- package/dist/issue-sticker-react.js +732 -133
- package/dist/{mouse-pointer-2-BR00y3ir.js → three-_bdgDAmI.js} +325 -28
- package/dist/{tooltip-DH02R32-.js → tooltip-UijEbdDX.js} +1 -1
- package/headless-react.d.ts +26 -0
- package/headless.d.ts +28 -0
- package/package.json +6 -2
- package/react.d.ts +28 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { c as createLucideIcon, u as ungzip_1, R as REPLAY_EVENT_TYPE, C as CANVAS_INTERACTION_TAG, a as cn, b as Replayer, M as MousePointer2 } from "./three-_bdgDAmI.js";
|
|
2
|
+
import { r } from "./three-_bdgDAmI.js";
|
|
1
3
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useRef, useState, useCallback,
|
|
3
|
-
import {
|
|
4
|
-
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-DH02R32-.js";
|
|
4
|
+
import { memo, useRef, useEffect, useState, useCallback, useMemo } from "react";
|
|
5
|
+
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-UijEbdDX.js";
|
|
5
6
|
/**
|
|
6
7
|
* @license lucide-react v0.468.0 - ISC
|
|
7
8
|
*
|
|
@@ -60,7 +61,8 @@ async function loadReplayEvents(url) {
|
|
|
60
61
|
const TYPE_LABEL = {
|
|
61
62
|
click: "클릭",
|
|
62
63
|
input: "입력",
|
|
63
|
-
nav: "이동"
|
|
64
|
+
nav: "이동",
|
|
65
|
+
canvas: "캔버스"
|
|
64
66
|
};
|
|
65
67
|
const NODE_TYPE_ELEMENT = 2;
|
|
66
68
|
const NODE_TYPE_TEXT = 3;
|
|
@@ -154,13 +156,21 @@ class NodeIndex {
|
|
|
154
156
|
return (firstClass ? `${tag}.${firstClass}` : `<${tag}>`).slice(0, 40);
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
|
-
const EVENT_TYPE_FULL_SNAPSHOT = 2;
|
|
158
|
-
const EVENT_TYPE_INCREMENTAL = 3;
|
|
159
|
-
const EVENT_TYPE_META = 4;
|
|
160
159
|
const SOURCE_MUTATION$1 = 0;
|
|
161
160
|
const SOURCE_MOUSE_INTERACTION = 2;
|
|
162
161
|
const SOURCE_INPUT = 5;
|
|
163
162
|
const MOUSE_CLICK = 2;
|
|
163
|
+
function canvasLabel(payload) {
|
|
164
|
+
if ((payload == null ? void 0 : payload.kind) === "external") {
|
|
165
|
+
return "화면 변경";
|
|
166
|
+
}
|
|
167
|
+
const isDrag = (payload == null ? void 0 : payload.kind) === "drag";
|
|
168
|
+
const target = payload == null ? void 0 : payload.target;
|
|
169
|
+
if (target) {
|
|
170
|
+
return isDrag ? `${target} 드래그` : target;
|
|
171
|
+
}
|
|
172
|
+
return isDrag ? "드래그" : "클릭";
|
|
173
|
+
}
|
|
164
174
|
function deriveTimeline(events) {
|
|
165
175
|
var _a;
|
|
166
176
|
const list = events;
|
|
@@ -169,12 +179,13 @@ function deriveTimeline(events) {
|
|
|
169
179
|
let recordedHeight = 0;
|
|
170
180
|
let seenFirstMeta = false;
|
|
171
181
|
const out = [];
|
|
182
|
+
const canvasFrames = [];
|
|
172
183
|
const index = new NodeIndex();
|
|
173
184
|
for (const ev of list) {
|
|
174
185
|
const ts = Number((ev == null ? void 0 : ev.timestamp) ?? 0);
|
|
175
186
|
const t = ts - startTime;
|
|
176
187
|
const data = (ev == null ? void 0 : ev.data) ?? {};
|
|
177
|
-
if ((ev == null ? void 0 : ev.type) ===
|
|
188
|
+
if ((ev == null ? void 0 : ev.type) === REPLAY_EVENT_TYPE.Meta) {
|
|
178
189
|
if (!seenFirstMeta) {
|
|
179
190
|
seenFirstMeta = true;
|
|
180
191
|
recordedWidth = Number(data.width ?? 0);
|
|
@@ -185,11 +196,33 @@ function deriveTimeline(events) {
|
|
|
185
196
|
out.push({ t, type: "nav", href, label: href || TYPE_LABEL.nav });
|
|
186
197
|
continue;
|
|
187
198
|
}
|
|
188
|
-
if ((ev == null ? void 0 : ev.type) ===
|
|
199
|
+
if ((ev == null ? void 0 : ev.type) === REPLAY_EVENT_TYPE.Custom) {
|
|
200
|
+
if (data.tag !== CANVAS_INTERACTION_TAG) continue;
|
|
201
|
+
const payload = data.payload;
|
|
202
|
+
if (payload == null ? void 0 : payload.snapshot) {
|
|
203
|
+
canvasFrames.push({
|
|
204
|
+
t,
|
|
205
|
+
nodeId: typeof payload.nodeId === "number" ? payload.nodeId : null,
|
|
206
|
+
canvasIndex: typeof payload.canvasIndex === "number" ? payload.canvasIndex : 0,
|
|
207
|
+
src: payload.snapshot,
|
|
208
|
+
...payload.baseline === true ? { baseline: true } : {}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if ((payload == null ? void 0 : payload.sampled) === true) continue;
|
|
212
|
+
out.push({
|
|
213
|
+
t,
|
|
214
|
+
type: "canvas",
|
|
215
|
+
label: canvasLabel(payload),
|
|
216
|
+
...(payload == null ? void 0 : payload.snapshot) ? { thumbnail: payload.snapshot } : {},
|
|
217
|
+
...typeof (payload == null ? void 0 : payload.nodeId) === "number" ? { nodeId: payload.nodeId } : {}
|
|
218
|
+
});
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if ((ev == null ? void 0 : ev.type) === REPLAY_EVENT_TYPE.FullSnapshot) {
|
|
189
222
|
index.reset(data.node);
|
|
190
223
|
continue;
|
|
191
224
|
}
|
|
192
|
-
if ((ev == null ? void 0 : ev.type) ===
|
|
225
|
+
if ((ev == null ? void 0 : ev.type) === REPLAY_EVENT_TYPE.IncrementalSnapshot) {
|
|
193
226
|
const source = Number(data.source);
|
|
194
227
|
if (source === SOURCE_MUTATION$1) {
|
|
195
228
|
for (const add of data.adds ?? []) {
|
|
@@ -204,11 +237,9 @@ function deriveTimeline(events) {
|
|
|
204
237
|
}
|
|
205
238
|
}
|
|
206
239
|
}
|
|
207
|
-
return { startTime, recordedWidth, recordedHeight, events: out };
|
|
240
|
+
return { startTime, recordedWidth, recordedHeight, events: out, canvasFrames };
|
|
208
241
|
}
|
|
209
242
|
const WIDGET_HOST_HTML_ID = "issue-sticker-host";
|
|
210
|
-
const EVENT_FULL_SNAPSHOT = 2;
|
|
211
|
-
const EVENT_INCREMENTAL = 3;
|
|
212
243
|
const NODE_ELEMENT = 2;
|
|
213
244
|
const SOURCE_MUTATION = 0;
|
|
214
245
|
const SOURCE_MOUSE_MOVE = 1;
|
|
@@ -314,13 +345,13 @@ function stripWidgetEvents(events) {
|
|
|
314
345
|
let removedEvents = 0;
|
|
315
346
|
for (const event of events) {
|
|
316
347
|
const ev = event;
|
|
317
|
-
if ((ev == null ? void 0 : ev.type) ===
|
|
348
|
+
if ((ev == null ? void 0 : ev.type) === REPLAY_EVENT_TYPE.FullSnapshot) {
|
|
318
349
|
const data2 = asRecord(ev.data);
|
|
319
350
|
const pruned = pruneTree(data2.node, widgetIds);
|
|
320
351
|
out.push(pruned === data2.node ? event : { ...ev, data: { ...data2, node: pruned } });
|
|
321
352
|
continue;
|
|
322
353
|
}
|
|
323
|
-
if ((ev == null ? void 0 : ev.type) !==
|
|
354
|
+
if ((ev == null ? void 0 : ev.type) !== REPLAY_EVENT_TYPE.IncrementalSnapshot) {
|
|
324
355
|
out.push(event);
|
|
325
356
|
continue;
|
|
326
357
|
}
|
|
@@ -368,10 +399,12 @@ const MOUSE_TAIL_CONFIG = {
|
|
|
368
399
|
};
|
|
369
400
|
const INITIAL_SHOW_TRAIL = true;
|
|
370
401
|
const SKIP_MS = 5e3;
|
|
402
|
+
const PAINT_RETRY_DEADLINE_MS = 5e3;
|
|
371
403
|
const TYPE_DOT = {
|
|
372
404
|
click: "bg-brand",
|
|
373
405
|
input: "bg-success",
|
|
374
|
-
nav: "bg-text-tertiary"
|
|
406
|
+
nav: "bg-text-tertiary",
|
|
407
|
+
canvas: "bg-warning"
|
|
375
408
|
};
|
|
376
409
|
function formatTime(ms) {
|
|
377
410
|
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
@@ -387,7 +420,18 @@ const EventLog = memo(function EventLog2({
|
|
|
387
420
|
onSeek,
|
|
388
421
|
total
|
|
389
422
|
}) {
|
|
390
|
-
const filtered = filter === "all" ? rows : rows.filter((
|
|
423
|
+
const filtered = filter === "all" ? rows : rows.filter((r2) => r2.type === filter);
|
|
424
|
+
const listRef = useRef(null);
|
|
425
|
+
useEffect(() => {
|
|
426
|
+
const list = listRef.current;
|
|
427
|
+
const row = list == null ? void 0 : list.querySelector(`[data-row-index="${currentIndex}"]`);
|
|
428
|
+
if (!list || !row) return;
|
|
429
|
+
const top = row.offsetTop;
|
|
430
|
+
const bottom = top + row.offsetHeight;
|
|
431
|
+
if (top < list.scrollTop || bottom > list.scrollTop + list.clientHeight) {
|
|
432
|
+
list.scrollTop = Math.max(0, top - (list.clientHeight - row.offsetHeight) / 2);
|
|
433
|
+
}
|
|
434
|
+
}, [currentIndex, filter]);
|
|
391
435
|
return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 min-w-0 flex-col rounded-md border border-line-subtle bg-surface-1", children: [
|
|
392
436
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-line-subtle px-3 py-2.5", children: [
|
|
393
437
|
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-text-primary", children: "이벤트 로그" }),
|
|
@@ -396,7 +440,7 @@ const EventLog = memo(function EventLog2({
|
|
|
396
440
|
total
|
|
397
441
|
] })
|
|
398
442
|
] }),
|
|
399
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-1.5 border-b border-line-subtle px-3 py-2", children: ["all", "click", "input", "nav"].map((f) => /* @__PURE__ */ jsx(
|
|
443
|
+
/* @__PURE__ */ jsx("div", { className: "flex gap-1.5 border-b border-line-subtle px-3 py-2", children: ["all", "click", "input", "nav", "canvas"].map((f) => /* @__PURE__ */ jsx(
|
|
400
444
|
"button",
|
|
401
445
|
{
|
|
402
446
|
type: "button",
|
|
@@ -409,12 +453,13 @@ const EventLog = memo(function EventLog2({
|
|
|
409
453
|
},
|
|
410
454
|
f
|
|
411
455
|
)) }),
|
|
412
|
-
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: filtered.map((row) => {
|
|
456
|
+
/* @__PURE__ */ jsx("div", { ref: listRef, className: "relative min-h-0 flex-1 overflow-auto", children: filtered.map((row) => {
|
|
413
457
|
const isCurrent = row.index === currentIndex;
|
|
414
458
|
return /* @__PURE__ */ jsxs(
|
|
415
459
|
"button",
|
|
416
460
|
{
|
|
417
461
|
type: "button",
|
|
462
|
+
"data-row-index": row.index,
|
|
418
463
|
onClick: () => onSeek(row.t),
|
|
419
464
|
className: cn(
|
|
420
465
|
"flex w-full items-center gap-2 border-b border-line-subtle px-3 py-2 text-left text-xs hover:bg-surface-2",
|
|
@@ -423,6 +468,14 @@ const EventLog = memo(function EventLog2({
|
|
|
423
468
|
children: [
|
|
424
469
|
/* @__PURE__ */ jsx("span", { className: "w-9 shrink-0 tabular-nums text-text-tertiary", children: formatTime(row.t) }),
|
|
425
470
|
/* @__PURE__ */ jsx("span", { className: cn("h-2 w-2 shrink-0 rounded-sm", TYPE_DOT[row.type]) }),
|
|
471
|
+
row.thumbnail && /* @__PURE__ */ jsx(
|
|
472
|
+
"img",
|
|
473
|
+
{
|
|
474
|
+
src: row.thumbnail,
|
|
475
|
+
alt: "",
|
|
476
|
+
className: "h-8 w-12 shrink-0 rounded-sm border border-line-subtle object-cover"
|
|
477
|
+
}
|
|
478
|
+
),
|
|
426
479
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-text-secondary", children: row.label }),
|
|
427
480
|
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-text-tertiary", children: TYPE_LABEL[row.type] })
|
|
428
481
|
]
|
|
@@ -432,6 +485,29 @@ const EventLog = memo(function EventLog2({
|
|
|
432
485
|
}) })
|
|
433
486
|
] });
|
|
434
487
|
});
|
|
488
|
+
async function waitForReplayCanvas(replayerRef, shot, cancelled) {
|
|
489
|
+
const deadline = Date.now() + PAINT_RETRY_DEADLINE_MS;
|
|
490
|
+
for (; ; ) {
|
|
491
|
+
if (cancelled()) return null;
|
|
492
|
+
const node = findReplayCanvas(replayerRef.current, shot);
|
|
493
|
+
if (node) return node;
|
|
494
|
+
if (Date.now() >= deadline) return null;
|
|
495
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function findReplayCanvas(replayer, shot) {
|
|
499
|
+
var _a, _b;
|
|
500
|
+
const replayDocument = (_a = replayer == null ? void 0 : replayer.iframe) == null ? void 0 : _a.contentDocument;
|
|
501
|
+
if (shot.nodeId !== null) {
|
|
502
|
+
const mirror = (_b = replayer == null ? void 0 : replayer.getMirror) == null ? void 0 : _b.call(replayer);
|
|
503
|
+
const node = mirror == null ? void 0 : mirror.getNode(shot.nodeId);
|
|
504
|
+
if (node && node.tagName === "CANVAS") {
|
|
505
|
+
return node;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
const candidate = replayDocument == null ? void 0 : replayDocument.querySelectorAll("canvas")[shot.canvasIndex];
|
|
509
|
+
return candidate && candidate.tagName === "CANVAS" ? candidate : null;
|
|
510
|
+
}
|
|
435
511
|
function SessionReplayPlayer({ url }) {
|
|
436
512
|
const rootRef = useRef(null);
|
|
437
513
|
const hostRef = useRef(null);
|
|
@@ -448,6 +524,9 @@ function SessionReplayPlayer({ url }) {
|
|
|
448
524
|
const [durationMs, setDurationMs] = useState(0);
|
|
449
525
|
const [currentMs, setCurrentMs] = useState(0);
|
|
450
526
|
const [timeline, setTimeline] = useState([]);
|
|
527
|
+
const [canvasShots, setCanvasShots] = useState([]);
|
|
528
|
+
const paintedCanvasRef = useRef(/* @__PURE__ */ new Map());
|
|
529
|
+
const [rebuildTick, setRebuildTick] = useState(0);
|
|
451
530
|
const [logRows, setLogRows] = useState([]);
|
|
452
531
|
const [filter, setFilter] = useState("all");
|
|
453
532
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
@@ -467,8 +546,8 @@ function SessionReplayPlayer({ url }) {
|
|
|
467
546
|
const startRaf = useCallback(() => {
|
|
468
547
|
stopRaf();
|
|
469
548
|
const tick = () => {
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
549
|
+
const r2 = replayerRef.current;
|
|
550
|
+
if (r2) setCurrentMs(Math.min(r2.getCurrentTime(), durationRef.current));
|
|
472
551
|
rafRef.current = requestAnimationFrame(tick);
|
|
473
552
|
};
|
|
474
553
|
rafRef.current = requestAnimationFrame(tick);
|
|
@@ -528,20 +607,31 @@ function SessionReplayPlayer({ url }) {
|
|
|
528
607
|
mouseTail: INITIAL_SHOW_TRAIL ? MOUSE_TAIL_CONFIG : false
|
|
529
608
|
}
|
|
530
609
|
);
|
|
610
|
+
replayer.on("fullsnapshot-rebuilded", () => {
|
|
611
|
+
if (cancelled) return;
|
|
612
|
+
setRebuildTick((tick) => tick + 1);
|
|
613
|
+
});
|
|
531
614
|
replayer.on("finish", () => {
|
|
532
615
|
if (cancelled) return;
|
|
533
616
|
applyIsPlaying(false);
|
|
534
617
|
startedRef.current = false;
|
|
535
618
|
stopRaf();
|
|
536
619
|
});
|
|
620
|
+
try {
|
|
621
|
+
replayer.pause(0);
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
537
624
|
replayerRef.current = replayer;
|
|
625
|
+
paintedCanvasRef.current.clear();
|
|
538
626
|
setTimeline(derived.events);
|
|
539
627
|
const totalTime = replayer.getMetaData().totalTime;
|
|
540
628
|
applyDuration(totalTime);
|
|
629
|
+
setCanvasShots(derived.canvasFrames);
|
|
541
630
|
const rows = derived.events.map((ev, i) => ({
|
|
542
631
|
t: ev.t,
|
|
543
632
|
type: ev.type,
|
|
544
633
|
label: ev.label,
|
|
634
|
+
...ev.thumbnail ? { thumbnail: ev.thumbnail } : {},
|
|
545
635
|
index: i
|
|
546
636
|
}));
|
|
547
637
|
setLogRows(rows);
|
|
@@ -567,32 +657,32 @@ function SessionReplayPlayer({ url }) {
|
|
|
567
657
|
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
568
658
|
}, []);
|
|
569
659
|
const seek = useCallback((ms) => {
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
660
|
+
const r2 = replayerRef.current;
|
|
661
|
+
if (!r2) return;
|
|
572
662
|
const clamped = Math.max(0, Math.min(ms, durationRef.current));
|
|
573
|
-
if (isPlayingRef.current)
|
|
574
|
-
else
|
|
663
|
+
if (isPlayingRef.current) r2.play(clamped);
|
|
664
|
+
else r2.pause(clamped);
|
|
575
665
|
startedRef.current = true;
|
|
576
666
|
setCurrentMs(clamped);
|
|
577
667
|
}, []);
|
|
578
668
|
const togglePlay = useCallback(() => {
|
|
579
|
-
const
|
|
580
|
-
if (!
|
|
669
|
+
const r2 = replayerRef.current;
|
|
670
|
+
if (!r2) return;
|
|
581
671
|
if (isPlayingRef.current) {
|
|
582
|
-
|
|
672
|
+
r2.pause();
|
|
583
673
|
applyIsPlaying(false);
|
|
584
674
|
stopRaf();
|
|
585
675
|
} else {
|
|
586
|
-
|
|
676
|
+
r2.play(startedRef.current ? r2.getCurrentTime() : 0);
|
|
587
677
|
startedRef.current = true;
|
|
588
678
|
applyIsPlaying(true);
|
|
589
679
|
startRaf();
|
|
590
680
|
}
|
|
591
681
|
}, [stopRaf, startRaf]);
|
|
592
682
|
const restart = useCallback(() => {
|
|
593
|
-
const
|
|
594
|
-
if (!
|
|
595
|
-
|
|
683
|
+
const r2 = replayerRef.current;
|
|
684
|
+
if (!r2) return;
|
|
685
|
+
r2.play(0);
|
|
596
686
|
startedRef.current = true;
|
|
597
687
|
applyIsPlaying(true);
|
|
598
688
|
startRaf();
|
|
@@ -634,6 +724,57 @@ function SessionReplayPlayer({ url }) {
|
|
|
634
724
|
[togglePlay, seek, currentMs, toggleFullscreen]
|
|
635
725
|
);
|
|
636
726
|
const currentIndex = logRows.reduce((acc, row) => row.t <= currentMs ? row.index : acc, -1);
|
|
727
|
+
const currentShots = useMemo(() => {
|
|
728
|
+
const byCanvas = /* @__PURE__ */ new Map();
|
|
729
|
+
for (const shot of canvasShots) {
|
|
730
|
+
const applies = shot.t <= currentMs || shot.baseline && !byCanvas.has(shot.canvasIndex);
|
|
731
|
+
if (applies) {
|
|
732
|
+
byCanvas.set(shot.canvasIndex, shot);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return Array.from(byCanvas.values());
|
|
736
|
+
}, [canvasShots, currentMs]);
|
|
737
|
+
const shotKey = currentShots.map((shot) => `${shot.canvasIndex}:${shot.t}`).join("|");
|
|
738
|
+
useEffect(() => {
|
|
739
|
+
let cancelled = false;
|
|
740
|
+
const painted = paintedCanvasRef.current;
|
|
741
|
+
const apply = async () => {
|
|
742
|
+
for (const shot of currentShots) {
|
|
743
|
+
const prev = painted.get(shot.canvasIndex);
|
|
744
|
+
if (prev && prev.src === shot.src && prev.rebuild === rebuildTick && prev.node.isConnected) {
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
const node = await waitForReplayCanvas(replayerRef, shot, () => cancelled);
|
|
748
|
+
if (cancelled || !node) {
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const image = new Image();
|
|
752
|
+
image.src = shot.src;
|
|
753
|
+
try {
|
|
754
|
+
await image.decode();
|
|
755
|
+
} catch {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
if (cancelled) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
node.style.backgroundImage = `url("${shot.src}")`;
|
|
762
|
+
node.style.backgroundSize = "100% 100%";
|
|
763
|
+
node.style.backgroundRepeat = "no-repeat";
|
|
764
|
+
painted.set(shot.canvasIndex, { node, src: shot.src, rebuild: rebuildTick });
|
|
765
|
+
}
|
|
766
|
+
for (const [canvasIndex, entry] of Array.from(painted.entries())) {
|
|
767
|
+
if (!currentShots.some((shot) => shot.canvasIndex === canvasIndex)) {
|
|
768
|
+
entry.node.style.backgroundImage = "";
|
|
769
|
+
painted.delete(canvasIndex);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
void apply();
|
|
774
|
+
return () => {
|
|
775
|
+
cancelled = true;
|
|
776
|
+
};
|
|
777
|
+
}, [shotKey, rebuildTick]);
|
|
637
778
|
if (state === "error") {
|
|
638
779
|
return /* @__PURE__ */ jsx("p", { className: "text-sm text-text-secondary", children: "리플레이를 불러오지 못했습니다." });
|
|
639
780
|
}
|
|
@@ -802,5 +943,6 @@ function SessionReplayViewer({ issue }) {
|
|
|
802
943
|
return /* @__PURE__ */ jsx(SessionReplayPlayer, { url });
|
|
803
944
|
}
|
|
804
945
|
export {
|
|
805
|
-
SessionReplayViewer
|
|
946
|
+
SessionReplayViewer,
|
|
947
|
+
r as registerThree
|
|
806
948
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { u as uploadScreenshotDataUrls, a as uploadSignedMediaWithApi, d as directUploadToSignedUrl, p as pristineFetch, g as getElementPosition, c as captureWithModernScreenshot, b as buildJiraCreateFields, e as buildNotionCreateFields, f as buildGuestOwnerQuery, h as composeIssueFilterGroups, i as buildIssueIntegrationsPayload, j as devLogger, C as ConsoleCollector, N as NetworkCollector, s as selectNetworkLogsForSubmit, k as filterExcludeServiceRelatedLogs, l as filterExcludeServiceRelatedConsoleLogs, m as compactNetworkLogsForTransport, n as CONSOLE_LOG_SUBMIT_LIMIT, o as buildExternalUserPayload, q as shrinkNetworkLogsToFit, r as measureJsonBytes, t as sanitizeString, v as getCurrentPageUrl, S as ScreenRecordingController,
|
|
1
|
+
import { u as uploadScreenshotDataUrls, a as uploadSignedMediaWithApi, d as directUploadToSignedUrl, p as pristineFetch, g as getElementPosition, c as captureWithModernScreenshot, b as buildJiraCreateFields, e as buildNotionCreateFields, f as buildGuestOwnerQuery, h as composeIssueFilterGroups, i as buildIssueIntegrationsPayload, j as devLogger, W as WebSocketCollector, C as ConsoleCollector, N as NetworkCollector, s as selectNetworkLogsForSubmit, k as filterExcludeServiceRelatedLogs, l as filterExcludeServiceRelatedConsoleLogs, m as compactNetworkLogsForTransport, n as CONSOLE_LOG_SUBMIT_LIMIT, o as buildExternalUserPayload, q as shrinkNetworkLogsToFit, r as measureJsonBytes, t as sanitizeString, v as serializeSocketTranscript, w as uploadSocketTranscript, x as getCurrentPageUrl, S as ScreenRecordingController, y as SessionReplayCaptureController, z as preloadModernScreenshot, I as ISSUE_STICKER_INTERNAL_LOG_PREFIX } from "./externalUserPayload-CVYSPfcx.js";
|
|
2
|
+
import { r } from "./three-_bdgDAmI.js";
|
|
2
3
|
import "react/jsx-runtime";
|
|
3
4
|
import "react";
|
|
4
|
-
import "./mouse-pointer-2-BR00y3ir.js";
|
|
5
5
|
const WINDOW_MS = 6e4;
|
|
6
6
|
const MAX_PER_WINDOW = 5;
|
|
7
7
|
class AutoIssueRateLimit {
|
|
@@ -854,7 +854,8 @@ class HeadlessIssueRepository {
|
|
|
854
854
|
}
|
|
855
855
|
const defaultDeps = {
|
|
856
856
|
createNetworkCollector: (apiBaseUrl) => new NetworkCollector(apiBaseUrl),
|
|
857
|
-
createConsoleCollector: () => new ConsoleCollector()
|
|
857
|
+
createConsoleCollector: () => new ConsoleCollector(),
|
|
858
|
+
createSocketCollector: (apiBaseUrl) => new WebSocketCollector(apiBaseUrl)
|
|
858
859
|
};
|
|
859
860
|
class HeadlessLogCollectors {
|
|
860
861
|
constructor(config, getApiBaseUrl2, deps = defaultDeps) {
|
|
@@ -863,9 +864,10 @@ class HeadlessLogCollectors {
|
|
|
863
864
|
this.deps = deps;
|
|
864
865
|
this.networkCollector = null;
|
|
865
866
|
this.consoleCollector = null;
|
|
867
|
+
this.socketCollector = null;
|
|
866
868
|
}
|
|
867
869
|
start() {
|
|
868
|
-
var _a, _b;
|
|
870
|
+
var _a, _b, _c, _d, _e;
|
|
869
871
|
if (((_a = this.config.capture) == null ? void 0 : _a.networkLogs) !== false && !this.networkCollector) {
|
|
870
872
|
this.networkCollector = this.deps.createNetworkCollector(this.getApiBaseUrl());
|
|
871
873
|
this.networkCollector.start();
|
|
@@ -874,13 +876,26 @@ class HeadlessLogCollectors {
|
|
|
874
876
|
this.consoleCollector = this.deps.createConsoleCollector();
|
|
875
877
|
this.consoleCollector.start();
|
|
876
878
|
}
|
|
879
|
+
if (((_c = this.config.capture) == null ? void 0 : _c.socketLogs) !== false && !this.socketCollector) {
|
|
880
|
+
const socket = this.deps.createSocketCollector(this.getApiBaseUrl());
|
|
881
|
+
this.socketCollector = socket;
|
|
882
|
+
(_e = (_d = this.networkCollector) == null ? void 0 : _d.bindSocketLogs) == null ? void 0 : _e.call(_d, () => socket.getNetworkLogs());
|
|
883
|
+
socket.start();
|
|
884
|
+
}
|
|
877
885
|
}
|
|
878
886
|
stop() {
|
|
879
|
-
var _a, _b;
|
|
887
|
+
var _a, _b, _c;
|
|
880
888
|
(_a = this.networkCollector) == null ? void 0 : _a.stop();
|
|
881
889
|
(_b = this.consoleCollector) == null ? void 0 : _b.stop();
|
|
890
|
+
(_c = this.socketCollector) == null ? void 0 : _c.stop();
|
|
882
891
|
this.networkCollector = null;
|
|
883
892
|
this.consoleCollector = null;
|
|
893
|
+
this.socketCollector = null;
|
|
894
|
+
}
|
|
895
|
+
/** 제출 시점에 소켓 전사를 만들 재료. 없으면 빈 배열 — serializeSocketTranscript 가 null 로 걸러낸다. */
|
|
896
|
+
getSocketConnections() {
|
|
897
|
+
var _a;
|
|
898
|
+
return ((_a = this.socketCollector) == null ? void 0 : _a.getConnections()) ?? [];
|
|
884
899
|
}
|
|
885
900
|
/**
|
|
886
901
|
* 스크린샷 캡처처럼 **우리가 서드파티 요청을 일으키는** 구간을 감싼다.
|
|
@@ -1107,6 +1122,7 @@ function buildIssueCreatePayload({
|
|
|
1107
1122
|
session_replay_upload_id: uploads.replayUpload.uploadId,
|
|
1108
1123
|
session_replay_meta: uploads.replayUpload.meta
|
|
1109
1124
|
} : {},
|
|
1125
|
+
...uploads.socketUpload ? { socket_log_upload_id: uploads.socketUpload.uploadId } : {},
|
|
1110
1126
|
console_logs: logs.consoleLogs.length > 0 ? logs.consoleLogs : void 0,
|
|
1111
1127
|
user_agent: userAgent,
|
|
1112
1128
|
tenant_id: auth.tenantId,
|
|
@@ -1138,18 +1154,27 @@ async function submitHeadlessIssueDraft({
|
|
|
1138
1154
|
logs,
|
|
1139
1155
|
currentUrl,
|
|
1140
1156
|
userAgent,
|
|
1141
|
-
uploadSessionReplaySnapshot
|
|
1157
|
+
uploadSessionReplaySnapshot,
|
|
1158
|
+
getSocketConnections
|
|
1142
1159
|
}) {
|
|
1143
1160
|
const screenshotUploads = draft.mediaMode === "screenshot" ? await transport.uploadScreenshotPreviews(draft.screenshotPreviewUrls) : [];
|
|
1144
1161
|
const screenshotUploadIds = screenshotUploads.map((upload) => upload.id);
|
|
1145
1162
|
const videoUpload = draft.mediaMode === "video" && pendingVideoFile ? await transport.uploadSignedMedia(pendingVideoFile, "video") : null;
|
|
1146
1163
|
const replayUpload = draft.sessionReplayEnabled ? await uploadSessionReplaySnapshot() : null;
|
|
1164
|
+
const socketSnapshot = await serializeSocketTranscript(getSocketConnections());
|
|
1165
|
+
const socketUpload = socketSnapshot ? await uploadSocketTranscript(
|
|
1166
|
+
{
|
|
1167
|
+
post: (endpoint, body) => transport.request(endpoint, { method: "POST", body }),
|
|
1168
|
+
directUpload: directUploadToSignedUrl
|
|
1169
|
+
},
|
|
1170
|
+
socketSnapshot
|
|
1171
|
+
) : null;
|
|
1147
1172
|
const { payload: issueData, stillOverBudget } = buildIssueCreatePayload({
|
|
1148
1173
|
draft,
|
|
1149
1174
|
auth,
|
|
1150
1175
|
config,
|
|
1151
1176
|
projectId,
|
|
1152
|
-
uploads: { screenshotUploadIds, videoUpload, replayUpload },
|
|
1177
|
+
uploads: { screenshotUploadIds, videoUpload, replayUpload, socketUpload },
|
|
1153
1178
|
logs,
|
|
1154
1179
|
currentUrl,
|
|
1155
1180
|
userAgent
|
|
@@ -1499,7 +1524,8 @@ class HeadlessClientImpl {
|
|
|
1499
1524
|
logs: this.logCollectors.collect(),
|
|
1500
1525
|
currentUrl: getCurrentPageUrl(),
|
|
1501
1526
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
1502
|
-
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot()
|
|
1527
|
+
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot(),
|
|
1528
|
+
getSocketConnections: () => this.logCollectors.getSocketConnections()
|
|
1503
1529
|
});
|
|
1504
1530
|
this.clearCaptureListeners();
|
|
1505
1531
|
this.clearPendingMedia();
|
|
@@ -1561,7 +1587,8 @@ class HeadlessClientImpl {
|
|
|
1561
1587
|
logs,
|
|
1562
1588
|
currentUrl: getCurrentPageUrl(),
|
|
1563
1589
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
1564
|
-
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot()
|
|
1590
|
+
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot(),
|
|
1591
|
+
getSocketConnections: () => this.logCollectors.getSocketConnections()
|
|
1565
1592
|
});
|
|
1566
1593
|
this.state.setSnapshot({
|
|
1567
1594
|
issues: [createdIssue, ...this.snapshot.issues]
|
|
@@ -1858,5 +1885,6 @@ function createIssueStickerHeadless(config) {
|
|
|
1858
1885
|
export {
|
|
1859
1886
|
IssueStickerHeadlessError,
|
|
1860
1887
|
createIssueStickerHeadless,
|
|
1861
|
-
createIssueStickerHeadless as default
|
|
1888
|
+
createIssueStickerHeadless as default,
|
|
1889
|
+
r as registerThree
|
|
1862
1890
|
};
|