issue-sticker 0.8.0 → 0.9.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/CHANGELOG.md +27 -0
- package/README.md +33 -0
- package/dist/{externalUserPayload-k9LSBeMB.js → externalUserPayload-CVp5Hz2L.js} +1027 -601
- package/dist/issue-sticker-headless-react.js +158 -22
- package/dist/issue-sticker-headless.js +43 -10
- package/dist/issue-sticker-react.js +442 -109
- package/dist/{mouse-pointer-2-BR00y3ir.js → three-B7nbYqGK.js} +855 -12
- package/dist/{tooltip-DH02R32-.js → tooltip-BBukUPo_.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, C as CANVAS_INTERACTION_TAG, a as cn, R as Replayer, M as MousePointer2 } from "./three-B7nbYqGK.js";
|
|
2
|
+
import { r } from "./three-B7nbYqGK.js";
|
|
1
3
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useRef, useState, useCallback, useEffect } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-DH02R32-.js";
|
|
4
|
+
import { memo, useRef, useState, useCallback, useEffect, useMemo } from "react";
|
|
5
|
+
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-BBukUPo_.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;
|
|
@@ -157,10 +159,22 @@ class NodeIndex {
|
|
|
157
159
|
const EVENT_TYPE_FULL_SNAPSHOT = 2;
|
|
158
160
|
const EVENT_TYPE_INCREMENTAL = 3;
|
|
159
161
|
const EVENT_TYPE_META = 4;
|
|
162
|
+
const EVENT_TYPE_CUSTOM = 5;
|
|
160
163
|
const SOURCE_MUTATION$1 = 0;
|
|
161
164
|
const SOURCE_MOUSE_INTERACTION = 2;
|
|
162
165
|
const SOURCE_INPUT = 5;
|
|
163
166
|
const MOUSE_CLICK = 2;
|
|
167
|
+
function canvasLabel(payload) {
|
|
168
|
+
if ((payload == null ? void 0 : payload.kind) === "external") {
|
|
169
|
+
return "화면 변경";
|
|
170
|
+
}
|
|
171
|
+
const isDrag = (payload == null ? void 0 : payload.kind) === "drag";
|
|
172
|
+
const target = payload == null ? void 0 : payload.target;
|
|
173
|
+
if (target) {
|
|
174
|
+
return isDrag ? `${target} 드래그` : target;
|
|
175
|
+
}
|
|
176
|
+
return isDrag ? "드래그" : "클릭";
|
|
177
|
+
}
|
|
164
178
|
function deriveTimeline(events) {
|
|
165
179
|
var _a;
|
|
166
180
|
const list = events;
|
|
@@ -169,6 +183,7 @@ function deriveTimeline(events) {
|
|
|
169
183
|
let recordedHeight = 0;
|
|
170
184
|
let seenFirstMeta = false;
|
|
171
185
|
const out = [];
|
|
186
|
+
const canvasFrames = [];
|
|
172
187
|
const index = new NodeIndex();
|
|
173
188
|
for (const ev of list) {
|
|
174
189
|
const ts = Number((ev == null ? void 0 : ev.timestamp) ?? 0);
|
|
@@ -185,6 +200,28 @@ function deriveTimeline(events) {
|
|
|
185
200
|
out.push({ t, type: "nav", href, label: href || TYPE_LABEL.nav });
|
|
186
201
|
continue;
|
|
187
202
|
}
|
|
203
|
+
if ((ev == null ? void 0 : ev.type) === EVENT_TYPE_CUSTOM) {
|
|
204
|
+
if (data.tag !== CANVAS_INTERACTION_TAG) continue;
|
|
205
|
+
const payload = data.payload;
|
|
206
|
+
if (payload == null ? void 0 : payload.snapshot) {
|
|
207
|
+
canvasFrames.push({
|
|
208
|
+
t,
|
|
209
|
+
nodeId: typeof payload.nodeId === "number" ? payload.nodeId : null,
|
|
210
|
+
canvasIndex: typeof payload.canvasIndex === "number" ? payload.canvasIndex : 0,
|
|
211
|
+
src: payload.snapshot,
|
|
212
|
+
...payload.baseline === true ? { baseline: true } : {}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if ((payload == null ? void 0 : payload.sampled) === true) continue;
|
|
216
|
+
out.push({
|
|
217
|
+
t,
|
|
218
|
+
type: "canvas",
|
|
219
|
+
label: canvasLabel(payload),
|
|
220
|
+
...(payload == null ? void 0 : payload.snapshot) ? { thumbnail: payload.snapshot } : {},
|
|
221
|
+
...typeof (payload == null ? void 0 : payload.nodeId) === "number" ? { nodeId: payload.nodeId } : {}
|
|
222
|
+
});
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
188
225
|
if ((ev == null ? void 0 : ev.type) === EVENT_TYPE_FULL_SNAPSHOT) {
|
|
189
226
|
index.reset(data.node);
|
|
190
227
|
continue;
|
|
@@ -204,7 +241,7 @@ function deriveTimeline(events) {
|
|
|
204
241
|
}
|
|
205
242
|
}
|
|
206
243
|
}
|
|
207
|
-
return { startTime, recordedWidth, recordedHeight, events: out };
|
|
244
|
+
return { startTime, recordedWidth, recordedHeight, events: out, canvasFrames };
|
|
208
245
|
}
|
|
209
246
|
const WIDGET_HOST_HTML_ID = "issue-sticker-host";
|
|
210
247
|
const EVENT_FULL_SNAPSHOT = 2;
|
|
@@ -368,10 +405,12 @@ const MOUSE_TAIL_CONFIG = {
|
|
|
368
405
|
};
|
|
369
406
|
const INITIAL_SHOW_TRAIL = true;
|
|
370
407
|
const SKIP_MS = 5e3;
|
|
408
|
+
const PAINT_RETRY_DEADLINE_MS = 5e3;
|
|
371
409
|
const TYPE_DOT = {
|
|
372
410
|
click: "bg-brand",
|
|
373
411
|
input: "bg-success",
|
|
374
|
-
nav: "bg-text-tertiary"
|
|
412
|
+
nav: "bg-text-tertiary",
|
|
413
|
+
canvas: "bg-warning"
|
|
375
414
|
};
|
|
376
415
|
function formatTime(ms) {
|
|
377
416
|
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
@@ -387,7 +426,7 @@ const EventLog = memo(function EventLog2({
|
|
|
387
426
|
onSeek,
|
|
388
427
|
total
|
|
389
428
|
}) {
|
|
390
|
-
const filtered = filter === "all" ? rows : rows.filter((
|
|
429
|
+
const filtered = filter === "all" ? rows : rows.filter((r2) => r2.type === filter);
|
|
391
430
|
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
431
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-line-subtle px-3 py-2.5", children: [
|
|
393
432
|
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-text-primary", children: "이벤트 로그" }),
|
|
@@ -396,7 +435,7 @@ const EventLog = memo(function EventLog2({
|
|
|
396
435
|
total
|
|
397
436
|
] })
|
|
398
437
|
] }),
|
|
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(
|
|
438
|
+
/* @__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
439
|
"button",
|
|
401
440
|
{
|
|
402
441
|
type: "button",
|
|
@@ -423,6 +462,14 @@ const EventLog = memo(function EventLog2({
|
|
|
423
462
|
children: [
|
|
424
463
|
/* @__PURE__ */ jsx("span", { className: "w-9 shrink-0 tabular-nums text-text-tertiary", children: formatTime(row.t) }),
|
|
425
464
|
/* @__PURE__ */ jsx("span", { className: cn("h-2 w-2 shrink-0 rounded-sm", TYPE_DOT[row.type]) }),
|
|
465
|
+
row.thumbnail && /* @__PURE__ */ jsx(
|
|
466
|
+
"img",
|
|
467
|
+
{
|
|
468
|
+
src: row.thumbnail,
|
|
469
|
+
alt: "",
|
|
470
|
+
className: "h-8 w-12 shrink-0 rounded-sm border border-line-subtle object-cover"
|
|
471
|
+
}
|
|
472
|
+
),
|
|
426
473
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-text-secondary", children: row.label }),
|
|
427
474
|
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-text-tertiary", children: TYPE_LABEL[row.type] })
|
|
428
475
|
]
|
|
@@ -432,6 +479,29 @@ const EventLog = memo(function EventLog2({
|
|
|
432
479
|
}) })
|
|
433
480
|
] });
|
|
434
481
|
});
|
|
482
|
+
async function waitForReplayCanvas(replayerRef, shot, cancelled) {
|
|
483
|
+
const deadline = Date.now() + PAINT_RETRY_DEADLINE_MS;
|
|
484
|
+
for (; ; ) {
|
|
485
|
+
if (cancelled()) return null;
|
|
486
|
+
const node = findReplayCanvas(replayerRef.current, shot);
|
|
487
|
+
if (node) return node;
|
|
488
|
+
if (Date.now() >= deadline) return null;
|
|
489
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function findReplayCanvas(replayer, shot) {
|
|
493
|
+
var _a, _b;
|
|
494
|
+
const replayDocument = (_a = replayer == null ? void 0 : replayer.iframe) == null ? void 0 : _a.contentDocument;
|
|
495
|
+
if (shot.nodeId !== null) {
|
|
496
|
+
const mirror = (_b = replayer == null ? void 0 : replayer.getMirror) == null ? void 0 : _b.call(replayer);
|
|
497
|
+
const node = mirror == null ? void 0 : mirror.getNode(shot.nodeId);
|
|
498
|
+
if (node && node.tagName === "CANVAS") {
|
|
499
|
+
return node;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const candidate = replayDocument == null ? void 0 : replayDocument.querySelectorAll("canvas")[shot.canvasIndex];
|
|
503
|
+
return candidate && candidate.tagName === "CANVAS" ? candidate : null;
|
|
504
|
+
}
|
|
435
505
|
function SessionReplayPlayer({ url }) {
|
|
436
506
|
const rootRef = useRef(null);
|
|
437
507
|
const hostRef = useRef(null);
|
|
@@ -448,6 +518,9 @@ function SessionReplayPlayer({ url }) {
|
|
|
448
518
|
const [durationMs, setDurationMs] = useState(0);
|
|
449
519
|
const [currentMs, setCurrentMs] = useState(0);
|
|
450
520
|
const [timeline, setTimeline] = useState([]);
|
|
521
|
+
const [canvasShots, setCanvasShots] = useState([]);
|
|
522
|
+
const paintedCanvasRef = useRef(/* @__PURE__ */ new Map());
|
|
523
|
+
const [rebuildTick, setRebuildTick] = useState(0);
|
|
451
524
|
const [logRows, setLogRows] = useState([]);
|
|
452
525
|
const [filter, setFilter] = useState("all");
|
|
453
526
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
@@ -467,8 +540,8 @@ function SessionReplayPlayer({ url }) {
|
|
|
467
540
|
const startRaf = useCallback(() => {
|
|
468
541
|
stopRaf();
|
|
469
542
|
const tick = () => {
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
543
|
+
const r2 = replayerRef.current;
|
|
544
|
+
if (r2) setCurrentMs(Math.min(r2.getCurrentTime(), durationRef.current));
|
|
472
545
|
rafRef.current = requestAnimationFrame(tick);
|
|
473
546
|
};
|
|
474
547
|
rafRef.current = requestAnimationFrame(tick);
|
|
@@ -528,20 +601,31 @@ function SessionReplayPlayer({ url }) {
|
|
|
528
601
|
mouseTail: INITIAL_SHOW_TRAIL ? MOUSE_TAIL_CONFIG : false
|
|
529
602
|
}
|
|
530
603
|
);
|
|
604
|
+
replayer.on("fullsnapshot-rebuilded", () => {
|
|
605
|
+
if (cancelled) return;
|
|
606
|
+
setRebuildTick((tick) => tick + 1);
|
|
607
|
+
});
|
|
531
608
|
replayer.on("finish", () => {
|
|
532
609
|
if (cancelled) return;
|
|
533
610
|
applyIsPlaying(false);
|
|
534
611
|
startedRef.current = false;
|
|
535
612
|
stopRaf();
|
|
536
613
|
});
|
|
614
|
+
try {
|
|
615
|
+
replayer.pause(0);
|
|
616
|
+
} catch {
|
|
617
|
+
}
|
|
537
618
|
replayerRef.current = replayer;
|
|
619
|
+
paintedCanvasRef.current.clear();
|
|
538
620
|
setTimeline(derived.events);
|
|
539
621
|
const totalTime = replayer.getMetaData().totalTime;
|
|
540
622
|
applyDuration(totalTime);
|
|
623
|
+
setCanvasShots(derived.canvasFrames);
|
|
541
624
|
const rows = derived.events.map((ev, i) => ({
|
|
542
625
|
t: ev.t,
|
|
543
626
|
type: ev.type,
|
|
544
627
|
label: ev.label,
|
|
628
|
+
...ev.thumbnail ? { thumbnail: ev.thumbnail } : {},
|
|
545
629
|
index: i
|
|
546
630
|
}));
|
|
547
631
|
setLogRows(rows);
|
|
@@ -567,32 +651,32 @@ function SessionReplayPlayer({ url }) {
|
|
|
567
651
|
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
568
652
|
}, []);
|
|
569
653
|
const seek = useCallback((ms) => {
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
654
|
+
const r2 = replayerRef.current;
|
|
655
|
+
if (!r2) return;
|
|
572
656
|
const clamped = Math.max(0, Math.min(ms, durationRef.current));
|
|
573
|
-
if (isPlayingRef.current)
|
|
574
|
-
else
|
|
657
|
+
if (isPlayingRef.current) r2.play(clamped);
|
|
658
|
+
else r2.pause(clamped);
|
|
575
659
|
startedRef.current = true;
|
|
576
660
|
setCurrentMs(clamped);
|
|
577
661
|
}, []);
|
|
578
662
|
const togglePlay = useCallback(() => {
|
|
579
|
-
const
|
|
580
|
-
if (!
|
|
663
|
+
const r2 = replayerRef.current;
|
|
664
|
+
if (!r2) return;
|
|
581
665
|
if (isPlayingRef.current) {
|
|
582
|
-
|
|
666
|
+
r2.pause();
|
|
583
667
|
applyIsPlaying(false);
|
|
584
668
|
stopRaf();
|
|
585
669
|
} else {
|
|
586
|
-
|
|
670
|
+
r2.play(startedRef.current ? r2.getCurrentTime() : 0);
|
|
587
671
|
startedRef.current = true;
|
|
588
672
|
applyIsPlaying(true);
|
|
589
673
|
startRaf();
|
|
590
674
|
}
|
|
591
675
|
}, [stopRaf, startRaf]);
|
|
592
676
|
const restart = useCallback(() => {
|
|
593
|
-
const
|
|
594
|
-
if (!
|
|
595
|
-
|
|
677
|
+
const r2 = replayerRef.current;
|
|
678
|
+
if (!r2) return;
|
|
679
|
+
r2.play(0);
|
|
596
680
|
startedRef.current = true;
|
|
597
681
|
applyIsPlaying(true);
|
|
598
682
|
startRaf();
|
|
@@ -634,6 +718,57 @@ function SessionReplayPlayer({ url }) {
|
|
|
634
718
|
[togglePlay, seek, currentMs, toggleFullscreen]
|
|
635
719
|
);
|
|
636
720
|
const currentIndex = logRows.reduce((acc, row) => row.t <= currentMs ? row.index : acc, -1);
|
|
721
|
+
const currentShots = useMemo(() => {
|
|
722
|
+
const byCanvas = /* @__PURE__ */ new Map();
|
|
723
|
+
for (const shot of canvasShots) {
|
|
724
|
+
const applies = shot.t <= currentMs || shot.baseline && !byCanvas.has(shot.canvasIndex);
|
|
725
|
+
if (applies) {
|
|
726
|
+
byCanvas.set(shot.canvasIndex, shot);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return Array.from(byCanvas.values());
|
|
730
|
+
}, [canvasShots, currentMs]);
|
|
731
|
+
const shotKey = currentShots.map((shot) => `${shot.canvasIndex}:${shot.t}`).join("|");
|
|
732
|
+
useEffect(() => {
|
|
733
|
+
let cancelled = false;
|
|
734
|
+
const painted = paintedCanvasRef.current;
|
|
735
|
+
const apply = async () => {
|
|
736
|
+
for (const shot of currentShots) {
|
|
737
|
+
const prev = painted.get(shot.canvasIndex);
|
|
738
|
+
if (prev && prev.src === shot.src && prev.rebuild === rebuildTick && prev.node.isConnected) {
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
const node = await waitForReplayCanvas(replayerRef, shot, () => cancelled);
|
|
742
|
+
if (cancelled || !node) {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
const image = new Image();
|
|
746
|
+
image.src = shot.src;
|
|
747
|
+
try {
|
|
748
|
+
await image.decode();
|
|
749
|
+
} catch {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (cancelled) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
node.style.backgroundImage = `url("${shot.src}")`;
|
|
756
|
+
node.style.backgroundSize = "100% 100%";
|
|
757
|
+
node.style.backgroundRepeat = "no-repeat";
|
|
758
|
+
painted.set(shot.canvasIndex, { node, src: shot.src, rebuild: rebuildTick });
|
|
759
|
+
}
|
|
760
|
+
for (const [canvasIndex, entry] of Array.from(painted.entries())) {
|
|
761
|
+
if (!currentShots.some((shot) => shot.canvasIndex === canvasIndex)) {
|
|
762
|
+
entry.node.style.backgroundImage = "";
|
|
763
|
+
painted.delete(canvasIndex);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
void apply();
|
|
768
|
+
return () => {
|
|
769
|
+
cancelled = true;
|
|
770
|
+
};
|
|
771
|
+
}, [shotKey, rebuildTick]);
|
|
637
772
|
if (state === "error") {
|
|
638
773
|
return /* @__PURE__ */ jsx("p", { className: "text-sm text-text-secondary", children: "리플레이를 불러오지 못했습니다." });
|
|
639
774
|
}
|
|
@@ -802,5 +937,6 @@ function SessionReplayViewer({ issue }) {
|
|
|
802
937
|
return /* @__PURE__ */ jsx(SessionReplayPlayer, { url });
|
|
803
938
|
}
|
|
804
939
|
export {
|
|
805
|
-
SessionReplayViewer
|
|
940
|
+
SessionReplayViewer,
|
|
941
|
+
r as registerThree
|
|
806
942
|
};
|
|
@@ -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-CVp5Hz2L.js";
|
|
2
|
+
import { r } from "./three-B7nbYqGK.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;
|
|
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,31 @@ 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
|
+
this.socketCollector = this.deps.createSocketCollector(this.getApiBaseUrl());
|
|
881
|
+
const network = this.networkCollector;
|
|
882
|
+
if (network) {
|
|
883
|
+
this.socketCollector.bindNetworkLogSink((log) => {
|
|
884
|
+
var _a2;
|
|
885
|
+
return (_a2 = network.ingest) == null ? void 0 : _a2.call(network, log);
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
this.socketCollector.start();
|
|
889
|
+
}
|
|
877
890
|
}
|
|
878
891
|
stop() {
|
|
879
|
-
var _a, _b;
|
|
892
|
+
var _a, _b, _c;
|
|
880
893
|
(_a = this.networkCollector) == null ? void 0 : _a.stop();
|
|
881
894
|
(_b = this.consoleCollector) == null ? void 0 : _b.stop();
|
|
895
|
+
(_c = this.socketCollector) == null ? void 0 : _c.stop();
|
|
882
896
|
this.networkCollector = null;
|
|
883
897
|
this.consoleCollector = null;
|
|
898
|
+
this.socketCollector = null;
|
|
899
|
+
}
|
|
900
|
+
/** 제출 시점에 소켓 전사를 만들 재료. 없으면 빈 배열 — serializeSocketTranscript 가 null 로 걸러낸다. */
|
|
901
|
+
getSocketConnections() {
|
|
902
|
+
var _a;
|
|
903
|
+
return ((_a = this.socketCollector) == null ? void 0 : _a.getConnections()) ?? [];
|
|
884
904
|
}
|
|
885
905
|
/**
|
|
886
906
|
* 스크린샷 캡처처럼 **우리가 서드파티 요청을 일으키는** 구간을 감싼다.
|
|
@@ -1107,6 +1127,7 @@ function buildIssueCreatePayload({
|
|
|
1107
1127
|
session_replay_upload_id: uploads.replayUpload.uploadId,
|
|
1108
1128
|
session_replay_meta: uploads.replayUpload.meta
|
|
1109
1129
|
} : {},
|
|
1130
|
+
...uploads.socketUpload ? { socket_log_upload_id: uploads.socketUpload.uploadId } : {},
|
|
1110
1131
|
console_logs: logs.consoleLogs.length > 0 ? logs.consoleLogs : void 0,
|
|
1111
1132
|
user_agent: userAgent,
|
|
1112
1133
|
tenant_id: auth.tenantId,
|
|
@@ -1138,18 +1159,27 @@ async function submitHeadlessIssueDraft({
|
|
|
1138
1159
|
logs,
|
|
1139
1160
|
currentUrl,
|
|
1140
1161
|
userAgent,
|
|
1141
|
-
uploadSessionReplaySnapshot
|
|
1162
|
+
uploadSessionReplaySnapshot,
|
|
1163
|
+
getSocketConnections
|
|
1142
1164
|
}) {
|
|
1143
1165
|
const screenshotUploads = draft.mediaMode === "screenshot" ? await transport.uploadScreenshotPreviews(draft.screenshotPreviewUrls) : [];
|
|
1144
1166
|
const screenshotUploadIds = screenshotUploads.map((upload) => upload.id);
|
|
1145
1167
|
const videoUpload = draft.mediaMode === "video" && pendingVideoFile ? await transport.uploadSignedMedia(pendingVideoFile, "video") : null;
|
|
1146
1168
|
const replayUpload = draft.sessionReplayEnabled ? await uploadSessionReplaySnapshot() : null;
|
|
1169
|
+
const socketSnapshot = await serializeSocketTranscript(getSocketConnections());
|
|
1170
|
+
const socketUpload = socketSnapshot ? await uploadSocketTranscript(
|
|
1171
|
+
{
|
|
1172
|
+
post: (endpoint, body) => transport.request(endpoint, { method: "POST", body }),
|
|
1173
|
+
directUpload: directUploadToSignedUrl
|
|
1174
|
+
},
|
|
1175
|
+
socketSnapshot
|
|
1176
|
+
) : null;
|
|
1147
1177
|
const { payload: issueData, stillOverBudget } = buildIssueCreatePayload({
|
|
1148
1178
|
draft,
|
|
1149
1179
|
auth,
|
|
1150
1180
|
config,
|
|
1151
1181
|
projectId,
|
|
1152
|
-
uploads: { screenshotUploadIds, videoUpload, replayUpload },
|
|
1182
|
+
uploads: { screenshotUploadIds, videoUpload, replayUpload, socketUpload },
|
|
1153
1183
|
logs,
|
|
1154
1184
|
currentUrl,
|
|
1155
1185
|
userAgent
|
|
@@ -1499,7 +1529,8 @@ class HeadlessClientImpl {
|
|
|
1499
1529
|
logs: this.logCollectors.collect(),
|
|
1500
1530
|
currentUrl: getCurrentPageUrl(),
|
|
1501
1531
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
1502
|
-
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot()
|
|
1532
|
+
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot(),
|
|
1533
|
+
getSocketConnections: () => this.logCollectors.getSocketConnections()
|
|
1503
1534
|
});
|
|
1504
1535
|
this.clearCaptureListeners();
|
|
1505
1536
|
this.clearPendingMedia();
|
|
@@ -1561,7 +1592,8 @@ class HeadlessClientImpl {
|
|
|
1561
1592
|
logs,
|
|
1562
1593
|
currentUrl: getCurrentPageUrl(),
|
|
1563
1594
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
|
|
1564
|
-
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot()
|
|
1595
|
+
uploadSessionReplaySnapshot: () => this.uploadSessionReplaySnapshot(),
|
|
1596
|
+
getSocketConnections: () => this.logCollectors.getSocketConnections()
|
|
1565
1597
|
});
|
|
1566
1598
|
this.state.setSnapshot({
|
|
1567
1599
|
issues: [createdIssue, ...this.snapshot.issues]
|
|
@@ -1858,5 +1890,6 @@ function createIssueStickerHeadless(config) {
|
|
|
1858
1890
|
export {
|
|
1859
1891
|
IssueStickerHeadlessError,
|
|
1860
1892
|
createIssueStickerHeadless,
|
|
1861
|
-
createIssueStickerHeadless as default
|
|
1893
|
+
createIssueStickerHeadless as default,
|
|
1894
|
+
r as registerThree
|
|
1862
1895
|
};
|