issue-sticker 0.4.0 → 0.5.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 +29 -0
- package/dist/{createLucideIcon-C0Ldhp96.js → createLucideIcon-BzRMP02h.js} +12 -12
- package/dist/{externalUserPayload-BVNl_35M.js → externalUserPayload-zu5IXBjn.js} +437 -182
- package/dist/issue-sticker-headless-react.js +2 -2
- package/dist/issue-sticker-headless.js +124 -15
- package/dist/issue-sticker-react.js +1690 -892
- package/dist/{tooltip-CEc_RGfI.js → tooltip-B6UPO-U8.js} +1 -1
- package/headless.d.ts +27 -2
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as OVERLAY_LAYER_INDEX, q as gzip_1, r as record, a as cn,
|
|
1
|
+
import { d as OVERLAY_LAYER_INDEX, q as gzip_1, r as record, a as cn, o as useCallbackRef$1, h as useComposedRefs, e as Primitive, P as Presence, i as Portal$1, f as composeEventHandlers, j as createContextScope, k as createSlot, D as DismissableLayer, C as Content, t as createPopperScope, l as useControllableState, v as Root2$1, m as useId, A as Anchor, w as Arrow, b as usePortalContainer, O as OVERLAY_LAYER, s as stopEscapePropagation, n as useLayoutEffect2, V as VISUALLY_HIDDEN_STYLES, c as createLucideIcon, x as clsx, S as Slot$2 } from "./createLucideIcon-BzRMP02h.js";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import React__default, { useState, createContext, useContext, useCallback, useRef, useLayoutEffect, useEffect, useMemo } from "react";
|
|
@@ -282,14 +282,63 @@ class ScreenRecordingController {
|
|
|
282
282
|
}
|
|
283
283
|
const SESSION_REPLAY_BLOCK_CLASS = "rr-block";
|
|
284
284
|
const SESSION_REPLAY_MASK_CLASS = "rr-mask";
|
|
285
|
+
const SESSION_REPLAY_UNMASK_CLASS = "rr-unmask";
|
|
285
286
|
const FOREIGN_BLOCK_SELECTORS = [
|
|
287
|
+
// FullStory
|
|
286
288
|
".fs-exclude",
|
|
289
|
+
".fs-block",
|
|
290
|
+
// Sentry — ignore 는 의미가 "입력 이벤트를 기록하지 않는다"라 차단과 어긋나지만,
|
|
291
|
+
// 빼면 이미 그것에 기대고 있는 고객에게 회귀다. 과잉 마스킹은 안전한 방향이라 둔다.
|
|
287
292
|
".sentry-block",
|
|
288
293
|
".sentry-ignore",
|
|
294
|
+
"[data-sentry-block]",
|
|
295
|
+
// PostHog
|
|
289
296
|
".ph-no-capture",
|
|
290
|
-
|
|
297
|
+
// Hotjar
|
|
298
|
+
"[data-hj-suppress]",
|
|
299
|
+
// OpenReplay
|
|
300
|
+
"[data-openreplay-hidden]",
|
|
301
|
+
// Highlight.io
|
|
302
|
+
".highlight-block",
|
|
303
|
+
".highlight-ignore",
|
|
304
|
+
// Heap
|
|
305
|
+
"[data-heap-ignore]",
|
|
306
|
+
".heap-ignore"
|
|
307
|
+
];
|
|
308
|
+
const FOREIGN_MASK_SELECTORS = [
|
|
309
|
+
// FullStory
|
|
310
|
+
".fs-mask",
|
|
311
|
+
// Sentry
|
|
312
|
+
".sentry-mask",
|
|
313
|
+
"[data-sentry-mask]",
|
|
314
|
+
// LogRocket
|
|
315
|
+
"[data-private]",
|
|
316
|
+
// Microsoft Clarity
|
|
317
|
+
"[data-clarity-mask]",
|
|
318
|
+
// Hotjar
|
|
319
|
+
"[data-hj-masked]",
|
|
320
|
+
// OpenReplay
|
|
321
|
+
"[data-openreplay-obscured]",
|
|
322
|
+
// Highlight.io
|
|
323
|
+
".highlight-mask",
|
|
324
|
+
// ContentSquare
|
|
325
|
+
"[data-cs-mask]",
|
|
326
|
+
"[data-cs-encrypt]",
|
|
327
|
+
// Heap
|
|
328
|
+
"[data-heap-redact-text]",
|
|
329
|
+
"[data-heap-redact-attributes]",
|
|
330
|
+
// Amplitude
|
|
331
|
+
"[data-amp-mask]",
|
|
332
|
+
// Matomo
|
|
333
|
+
"[data-matomo-mask]"
|
|
334
|
+
];
|
|
335
|
+
const FOREIGN_UNMASK_SELECTORS = [
|
|
336
|
+
".fs-unmask",
|
|
337
|
+
".sentry-unmask",
|
|
338
|
+
"[data-clarity-unmask]",
|
|
339
|
+
"[data-amp-unmask]",
|
|
340
|
+
"[data-cs-capture]"
|
|
291
341
|
];
|
|
292
|
-
const FOREIGN_MASK_SELECTORS = [".fs-mask", ".sentry-mask"];
|
|
293
342
|
const SESSION_REPLAY_FULL_MASK_SELECTOR = [
|
|
294
343
|
`.${SESSION_REPLAY_MASK_CLASS}`,
|
|
295
344
|
...FOREIGN_MASK_SELECTORS
|
|
@@ -298,11 +347,25 @@ const SESSION_REPLAY_BLOCK_SELECTOR = [
|
|
|
298
347
|
`.${SESSION_REPLAY_BLOCK_CLASS}`,
|
|
299
348
|
...FOREIGN_BLOCK_SELECTORS
|
|
300
349
|
].join(",");
|
|
350
|
+
const SESSION_REPLAY_UNMASK_SELECTOR = [
|
|
351
|
+
`.${SESSION_REPLAY_UNMASK_CLASS}`,
|
|
352
|
+
...FOREIGN_UNMASK_SELECTORS
|
|
353
|
+
].join(",");
|
|
354
|
+
function isElementFullyMasked(element, maskSelector = SESSION_REPLAY_FULL_MASK_SELECTOR, unmaskSelector = SESSION_REPLAY_UNMASK_SELECTOR) {
|
|
355
|
+
if (!element) return false;
|
|
356
|
+
try {
|
|
357
|
+
const nearest = element.closest(`${maskSelector},${unmaskSelector}`);
|
|
358
|
+
return nearest !== null && nearest.matches(maskSelector);
|
|
359
|
+
} catch {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
301
363
|
const DEFAULT_PRIVACY_CONFIG_V2 = {
|
|
302
364
|
version: "v2",
|
|
303
365
|
maskAllInputs: true,
|
|
304
366
|
maskTextSelector: "*",
|
|
305
367
|
fullMaskSelector: SESSION_REPLAY_FULL_MASK_SELECTOR,
|
|
368
|
+
unmaskSelector: SESSION_REPLAY_UNMASK_SELECTOR,
|
|
306
369
|
blockSelector: SESSION_REPLAY_BLOCK_SELECTOR,
|
|
307
370
|
allowCanvasRecording: false
|
|
308
371
|
};
|
|
@@ -324,7 +387,8 @@ function appendEvent(segments, event, isCheckout) {
|
|
|
324
387
|
}
|
|
325
388
|
return copy;
|
|
326
389
|
}
|
|
327
|
-
function trimSegments(segments, windowMs, now) {
|
|
390
|
+
function trimSegments(segments, windowMs, now, checkoutMs) {
|
|
391
|
+
var _a, _b;
|
|
328
392
|
const cutoff = now - windowMs;
|
|
329
393
|
let startIdx = 0;
|
|
330
394
|
for (let i2 = 0; i2 < segments.length; i2 += 1) {
|
|
@@ -334,6 +398,10 @@ function trimSegments(segments, windowMs, now) {
|
|
|
334
398
|
startIdx = i2;
|
|
335
399
|
}
|
|
336
400
|
}
|
|
401
|
+
const headStart = (_b = (_a = segments[startIdx]) == null ? void 0 : _a.events[0]) == null ? void 0 : _b.timestamp;
|
|
402
|
+
if (checkoutMs !== void 0 && headStart !== void 0 && headStart < cutoff - checkoutMs && startIdx < segments.length - 1) {
|
|
403
|
+
startIdx += 1;
|
|
404
|
+
}
|
|
337
405
|
return segments.slice(startIdx);
|
|
338
406
|
}
|
|
339
407
|
function flattenEvents(segments) {
|
|
@@ -518,6 +586,12 @@ const RRN_CANDIDATE_PATTERN = /\b(\d{2})(\d{2})(\d{2})-?([1-8])(\d{6})\b/g;
|
|
|
518
586
|
const BRN_CANDIDATE_PATTERN = /\b(\d{3})-?(\d{2})-?(\d{5})\b/g;
|
|
519
587
|
const BRN_WEIGHTS = [1, 3, 7, 1, 3, 7, 1, 3, 5];
|
|
520
588
|
const KR_MOBILE_PATTERN = /\b01[016789]-?\d{3,4}-?\d{4}\b/g;
|
|
589
|
+
const EMAIL_PATTERN = /[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+/g;
|
|
590
|
+
function redactEmails(text) {
|
|
591
|
+
if (!text) return text;
|
|
592
|
+
const out = text.replace(EMAIL_PATTERN, REDACTED_BODY_VALUE);
|
|
593
|
+
return out === text ? text : out;
|
|
594
|
+
}
|
|
521
595
|
function passesBrnChecksum(digits) {
|
|
522
596
|
let sum = 0;
|
|
523
597
|
for (let i2 = 0; i2 < 9; i2 += 1) {
|
|
@@ -664,17 +738,17 @@ function redactReplayEvents(events) {
|
|
|
664
738
|
}
|
|
665
739
|
return events;
|
|
666
740
|
}
|
|
667
|
-
const RRWEB_VERSION = "2.
|
|
741
|
+
const RRWEB_VERSION = "2.1.0";
|
|
668
742
|
const SESSION_REPLAY_WINDOW_MS = 12e4;
|
|
669
743
|
const SESSION_REPLAY_CHECKOUT_MS = 6e4;
|
|
670
744
|
const REPLAY_MASK_VALUE = "[redacted]";
|
|
671
745
|
function maskReplayInput(text) {
|
|
672
746
|
return text ? REPLAY_MASK_VALUE : text;
|
|
673
747
|
}
|
|
674
|
-
function createMaskTextFn(fullMaskSelector) {
|
|
748
|
+
function createMaskTextFn(fullMaskSelector, unmaskSelector) {
|
|
675
749
|
return (text, element) => {
|
|
676
750
|
try {
|
|
677
|
-
if (fullMaskSelector && (element
|
|
751
|
+
if (fullMaskSelector && isElementFullyMasked(element, fullMaskSelector, unmaskSelector)) {
|
|
678
752
|
return REPLAY_MASK_VALUE;
|
|
679
753
|
}
|
|
680
754
|
return redactSensitiveValues(text);
|
|
@@ -684,12 +758,21 @@ function createMaskTextFn(fullMaskSelector) {
|
|
|
684
758
|
};
|
|
685
759
|
}
|
|
686
760
|
const IDLE_CHECKOUT_POLL_MS = 5e3;
|
|
761
|
+
function spanSeconds(segments) {
|
|
762
|
+
var _a, _b;
|
|
763
|
+
const events = flattenEvents(segments);
|
|
764
|
+
const first = (_a = events[0]) == null ? void 0 : _a.timestamp;
|
|
765
|
+
const last = (_b = events[events.length - 1]) == null ? void 0 : _b.timestamp;
|
|
766
|
+
if (first === void 0 || last === void 0) return 0;
|
|
767
|
+
return Math.round((last - first) / 1e3);
|
|
768
|
+
}
|
|
687
769
|
class RingBufferRecorder {
|
|
688
770
|
constructor(options = {}) {
|
|
689
771
|
this.options = options;
|
|
690
772
|
this.segments = createSegments();
|
|
691
773
|
this.stopFn = null;
|
|
692
774
|
this.idleCheckoutTimer = null;
|
|
775
|
+
this.visibilityListener = null;
|
|
693
776
|
this.tailCutoff = null;
|
|
694
777
|
}
|
|
695
778
|
get windowMs() {
|
|
@@ -710,8 +793,13 @@ class RingBufferRecorder {
|
|
|
710
793
|
/**
|
|
711
794
|
* 유휴가 길어 경계가 없으면 FullSnapshot 을 강제로 찍는다.
|
|
712
795
|
*
|
|
713
|
-
* 숨은 탭에서는 건너뛴다 — 보이지도 않는 페이지의 DOM 을 주기적으로 직렬화할
|
|
714
|
-
* 다시
|
|
796
|
+
* 숨은 탭에서는 주기 검사를 건너뛴다 — 보이지도 않는 페이지의 DOM 을 주기적으로 직렬화할
|
|
797
|
+
* 이유가 없다. 대신 다시 보이는 순간 `visibilitychange` 로 여기를 한 번 더 부른다.
|
|
798
|
+
* 다음 폴링을 기다리면 그 사이에 스냅샷을 뜰 때 과길이 버퍼가 그대로 올라간다.
|
|
799
|
+
*
|
|
800
|
+
* rrweb 은 `recording` 이 false 면 던진다. 그 값은 모듈 전역이라 옛 recorder 의 stop 이
|
|
801
|
+
* 늦게 돌면 살아 있는 recorder 의 인터벌이 5초마다 던지게 된다. 고객 페이지에서 도는
|
|
802
|
+
* 코드라 밖으로 새면 안 된다.
|
|
715
803
|
*/
|
|
716
804
|
forceCheckoutIfIdle() {
|
|
717
805
|
var _a;
|
|
@@ -720,7 +808,10 @@ class RingBufferRecorder {
|
|
|
720
808
|
if (start === null) return;
|
|
721
809
|
if (this.nowFn() - start < this.checkoutEveryMs) return;
|
|
722
810
|
const recordFn = this.options.recordFn ?? record;
|
|
723
|
-
|
|
811
|
+
try {
|
|
812
|
+
(_a = recordFn.takeFullSnapshot) == null ? void 0 : _a.call(recordFn, true);
|
|
813
|
+
} catch {
|
|
814
|
+
}
|
|
724
815
|
}
|
|
725
816
|
start() {
|
|
726
817
|
if (this.stopFn) return;
|
|
@@ -732,20 +823,24 @@ class RingBufferRecorder {
|
|
|
732
823
|
emit: (event, isCheckout) => {
|
|
733
824
|
var _a, _b;
|
|
734
825
|
this.segments = appendEvent(this.segments, event, Boolean(isCheckout));
|
|
735
|
-
this.segments = trimSegments(this.segments, this.windowMs, now());
|
|
826
|
+
this.segments = trimSegments(this.segments, this.windowMs, now(), this.checkoutEveryMs);
|
|
736
827
|
(_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a);
|
|
737
828
|
},
|
|
738
829
|
checkoutEveryNms: this.options.checkoutEveryNms ?? SESSION_REPLAY_CHECKOUT_MS,
|
|
739
830
|
maskAllInputs: cfg.maskAllInputs,
|
|
740
831
|
blockSelector: cfg.blockSelector,
|
|
741
832
|
maskTextSelector: cfg.maskTextSelector,
|
|
742
|
-
maskTextFn: createMaskTextFn(cfg.fullMaskSelector),
|
|
833
|
+
maskTextFn: createMaskTextFn(cfg.fullMaskSelector, cfg.unmaskSelector),
|
|
743
834
|
maskInputFn: maskReplayInput,
|
|
744
835
|
recordCanvas: cfg.allowCanvasRecording
|
|
745
836
|
// rrweb 옵션 타입이 버전별로 달라 캐스팅한다.
|
|
746
837
|
});
|
|
747
838
|
this.stopFn = typeof stop === "function" ? stop : null;
|
|
748
839
|
this.idleCheckoutTimer = setInterval(() => this.forceCheckoutIfIdle(), IDLE_CHECKOUT_POLL_MS);
|
|
840
|
+
if (typeof document !== "undefined") {
|
|
841
|
+
this.visibilityListener = () => this.forceCheckoutIfIdle();
|
|
842
|
+
document.addEventListener("visibilitychange", this.visibilityListener);
|
|
843
|
+
}
|
|
749
844
|
}
|
|
750
845
|
stop() {
|
|
751
846
|
var _a;
|
|
@@ -755,6 +850,10 @@ class RingBufferRecorder {
|
|
|
755
850
|
clearInterval(this.idleCheckoutTimer);
|
|
756
851
|
this.idleCheckoutTimer = null;
|
|
757
852
|
}
|
|
853
|
+
if (this.visibilityListener !== null) {
|
|
854
|
+
document.removeEventListener("visibilitychange", this.visibilityListener);
|
|
855
|
+
this.visibilityListener = null;
|
|
856
|
+
}
|
|
758
857
|
}
|
|
759
858
|
/**
|
|
760
859
|
* 이슈 생성 단계의 시작을 표시한다. 이 시각 이후는 스냅샷에서 빠진다.
|
|
@@ -790,17 +889,30 @@ class RingBufferRecorder {
|
|
|
790
889
|
restore(segments) {
|
|
791
890
|
var _a, _b;
|
|
792
891
|
if (segments.length === 0) return;
|
|
793
|
-
this.segments = trimSegments(
|
|
892
|
+
this.segments = trimSegments(
|
|
893
|
+
[...segments, ...this.segments],
|
|
894
|
+
this.windowMs,
|
|
895
|
+
this.nowFn(),
|
|
896
|
+
this.checkoutEveryMs
|
|
897
|
+
);
|
|
794
898
|
(_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a);
|
|
795
899
|
}
|
|
796
|
-
/**
|
|
900
|
+
/**
|
|
901
|
+
* 현재 버퍼를 업로드 가능한 스냅샷으로 직렬화한다.
|
|
902
|
+
*
|
|
903
|
+
* 여기서도 한 번 더 트림한다. emit 시점의 트림만으로는 마지막 이벤트 이후 흐른 시간이
|
|
904
|
+
* 무제한으로 실린다. 기준 시각은 꼬리 컷오프가 있으면 그 시점이다 — 폼을 채우는 동안
|
|
905
|
+
* 흐른 시간 때문에 버그 직전 구간이 밀려나면 안 된다.
|
|
906
|
+
*/
|
|
797
907
|
async snapshot() {
|
|
798
908
|
const cfg = resolvePrivacyConfig(this.options.privacyConfig);
|
|
799
|
-
const
|
|
909
|
+
const until = this.tailCutoff ?? this.nowFn();
|
|
910
|
+
const trimmed = trimSegments(this.segments, this.windowMs, until, this.checkoutEveryMs);
|
|
911
|
+
const segments = this.tailCutoff === null ? trimmed : dropEventsAfter(trimmed, this.tailCutoff);
|
|
800
912
|
return serializeSnapshot({
|
|
801
913
|
segments,
|
|
802
914
|
redactEvents: redactReplayEvents,
|
|
803
|
-
windowSeconds:
|
|
915
|
+
windowSeconds: spanSeconds(segments),
|
|
804
916
|
rrwebVersion: RRWEB_VERSION,
|
|
805
917
|
privacyConfigVersion: cfg.version
|
|
806
918
|
});
|
|
@@ -1231,27 +1343,11 @@ function createReplaySession(options = {}) {
|
|
|
1231
1343
|
}
|
|
1232
1344
|
};
|
|
1233
1345
|
}
|
|
1234
|
-
const STORAGE_KEY = "issue-sticker-session-replay-attach:v1";
|
|
1235
|
-
function getReplayAttachPreference() {
|
|
1236
|
-
try {
|
|
1237
|
-
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
1238
|
-
if (raw === null) return true;
|
|
1239
|
-
return raw !== "off";
|
|
1240
|
-
} catch {
|
|
1241
|
-
return true;
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
function setReplayAttachPreference(enabled) {
|
|
1245
|
-
try {
|
|
1246
|
-
window.localStorage.setItem(STORAGE_KEY, enabled ? "on" : "off");
|
|
1247
|
-
} catch {
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
1346
|
function createInitialSnapshot() {
|
|
1251
1347
|
return {
|
|
1252
1348
|
available: false,
|
|
1253
1349
|
canAttach: false,
|
|
1254
|
-
enabled:
|
|
1350
|
+
enabled: true,
|
|
1255
1351
|
error: null
|
|
1256
1352
|
};
|
|
1257
1353
|
}
|
|
@@ -1312,7 +1408,6 @@ class SessionReplayCaptureController {
|
|
|
1312
1408
|
}
|
|
1313
1409
|
}
|
|
1314
1410
|
setEnabled(enabled) {
|
|
1315
|
-
setReplayAttachPreference(enabled);
|
|
1316
1411
|
this.setSnapshot({ enabled });
|
|
1317
1412
|
}
|
|
1318
1413
|
/** 이슈 폼이 열렸다. 이후 구간은 리플레이에서 빠진다. */
|
|
@@ -1350,10 +1445,189 @@ class SessionReplayCaptureController {
|
|
|
1350
1445
|
this.listeners.forEach((listener) => listener(this.snapshot));
|
|
1351
1446
|
}
|
|
1352
1447
|
}
|
|
1448
|
+
function forEachElementDeep(root, callback) {
|
|
1449
|
+
if (root instanceof Element) {
|
|
1450
|
+
callback(root);
|
|
1451
|
+
if (root.shadowRoot) {
|
|
1452
|
+
forEachElementDeep(root.shadowRoot, callback);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
Array.from(root.children).forEach((child) => {
|
|
1456
|
+
forEachElementDeep(child, callback);
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
const SCREENSHOT_FULL_MASK_SELECTOR = SESSION_REPLAY_FULL_MASK_SELECTOR;
|
|
1460
|
+
const SCREENSHOT_BLOCK_SELECTOR = SESSION_REPLAY_BLOCK_SELECTOR;
|
|
1461
|
+
const SCREENSHOT_MASK_BACKGROUND = "rgba(148, 148, 148, 0.28)";
|
|
1462
|
+
const SCREENSHOT_BLOCK_BACKGROUND = "rgba(148, 148, 148, 0.85)";
|
|
1463
|
+
const MASK_LABEL_WIDTH = 44;
|
|
1464
|
+
const MASK_LABEL_HEIGHT = 16;
|
|
1465
|
+
const MASK_LABEL_IMAGE = `url("data:image/svg+xml;charset=utf-8,${encodeURIComponent(
|
|
1466
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${MASK_LABEL_WIDTH}" height="${MASK_LABEL_HEIGHT}" viewBox="0 0 ${MASK_LABEL_WIDTH} ${MASK_LABEL_HEIGHT}"><text x="${MASK_LABEL_WIDTH / 2}" y="12" text-anchor="middle" font-family="sans-serif" font-size="11" font-weight="600" fill="#262626">가려짐</text></svg>`
|
|
1467
|
+
)}")`;
|
|
1468
|
+
const MASK_LABEL_MIN_WIDTH = MASK_LABEL_WIDTH + 8;
|
|
1469
|
+
const MASK_LABEL_MIN_HEIGHT = MASK_LABEL_HEIGHT + 8;
|
|
1470
|
+
const TEXT_HIDING_PROPERTIES = [
|
|
1471
|
+
["color", "transparent"],
|
|
1472
|
+
["-webkit-text-fill-color", "transparent"],
|
|
1473
|
+
["text-shadow", "none"],
|
|
1474
|
+
["fill", "transparent"]
|
|
1475
|
+
];
|
|
1476
|
+
const REPLACED_MEDIA_SELECTOR = "img, svg, video, canvas, picture, iframe, object, embed";
|
|
1477
|
+
const VALUE_ELEMENT_SELECTOR = "input, textarea, select";
|
|
1478
|
+
const SENSITIVE_AUTOCOMPLETE_TOKENS = /* @__PURE__ */ new Set([
|
|
1479
|
+
// 자격증명
|
|
1480
|
+
"current-password",
|
|
1481
|
+
"new-password",
|
|
1482
|
+
"one-time-code",
|
|
1483
|
+
// 결제
|
|
1484
|
+
"cc-number",
|
|
1485
|
+
"cc-exp",
|
|
1486
|
+
"cc-exp-month",
|
|
1487
|
+
"cc-exp-year",
|
|
1488
|
+
"cc-csc",
|
|
1489
|
+
"cc-name",
|
|
1490
|
+
"cc-type",
|
|
1491
|
+
"cc-given-name",
|
|
1492
|
+
"cc-additional-name",
|
|
1493
|
+
"cc-family-name",
|
|
1494
|
+
// 신원
|
|
1495
|
+
"name",
|
|
1496
|
+
"given-name",
|
|
1497
|
+
"additional-name",
|
|
1498
|
+
"family-name",
|
|
1499
|
+
"honorific-prefix",
|
|
1500
|
+
"honorific-suffix",
|
|
1501
|
+
"nickname",
|
|
1502
|
+
"bday",
|
|
1503
|
+
"bday-day",
|
|
1504
|
+
"bday-month",
|
|
1505
|
+
"bday-year",
|
|
1506
|
+
"sex",
|
|
1507
|
+
// 주소
|
|
1508
|
+
"street-address",
|
|
1509
|
+
"address-line1",
|
|
1510
|
+
"address-line2",
|
|
1511
|
+
"address-line3",
|
|
1512
|
+
"postal-code",
|
|
1513
|
+
// 연락처
|
|
1514
|
+
"tel",
|
|
1515
|
+
"tel-national",
|
|
1516
|
+
"tel-local",
|
|
1517
|
+
"tel-area-code",
|
|
1518
|
+
"email",
|
|
1519
|
+
"impp"
|
|
1520
|
+
]);
|
|
1521
|
+
function redactScreenshotText(text) {
|
|
1522
|
+
return redactEmails(redactSensitiveValues(text));
|
|
1523
|
+
}
|
|
1524
|
+
function matchesSafely(element, selector) {
|
|
1525
|
+
try {
|
|
1526
|
+
return element.matches(selector);
|
|
1527
|
+
} catch {
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
function closestSafely(element, selector) {
|
|
1532
|
+
if (!element) return null;
|
|
1533
|
+
try {
|
|
1534
|
+
return element.closest(selector);
|
|
1535
|
+
} catch {
|
|
1536
|
+
return null;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
function hasSensitiveValueHint(element) {
|
|
1540
|
+
var _a;
|
|
1541
|
+
if (((_a = element.getAttribute("type")) == null ? void 0 : _a.toLowerCase()) === "password") {
|
|
1542
|
+
return true;
|
|
1543
|
+
}
|
|
1544
|
+
const autocomplete = element.getAttribute("autocomplete");
|
|
1545
|
+
if (!autocomplete) return false;
|
|
1546
|
+
return autocomplete.toLowerCase().split(/\s+/).some((token) => SENSITIVE_AUTOCOMPLETE_TOKENS.has(token));
|
|
1547
|
+
}
|
|
1548
|
+
const overwriteProperty = (element, name, value) => {
|
|
1549
|
+
const style = element.style;
|
|
1550
|
+
style == null ? void 0 : style.setProperty(name, value, "important");
|
|
1551
|
+
};
|
|
1552
|
+
function coverMaskedRegion(region, setProperty) {
|
|
1553
|
+
setProperty(region, "background-color", SCREENSHOT_MASK_BACKGROUND);
|
|
1554
|
+
forEachElementDeep(region, (node) => {
|
|
1555
|
+
if (!isElementFullyMasked(node)) return;
|
|
1556
|
+
TEXT_HIDING_PROPERTIES.forEach(([name, value]) => setProperty(node, name, value));
|
|
1557
|
+
if (matchesSafely(node, REPLACED_MEDIA_SELECTOR)) {
|
|
1558
|
+
setProperty(node, "visibility", "hidden");
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
function parsePixels(value) {
|
|
1563
|
+
const parsed = Number.parseFloat(value ?? "");
|
|
1564
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
1565
|
+
}
|
|
1566
|
+
function fitsMaskLabel(region) {
|
|
1567
|
+
const rect = region.getBoundingClientRect();
|
|
1568
|
+
const style = region.style;
|
|
1569
|
+
const width = rect.width || parsePixels(style == null ? void 0 : style.width);
|
|
1570
|
+
const height = rect.height || parsePixels(style == null ? void 0 : style.height);
|
|
1571
|
+
return width >= MASK_LABEL_MIN_WIDTH && height >= MASK_LABEL_MIN_HEIGHT;
|
|
1572
|
+
}
|
|
1573
|
+
function coverBlockedRegion(region, setProperty) {
|
|
1574
|
+
const labeled = fitsMaskLabel(region);
|
|
1575
|
+
setProperty(region, "visibility", "visible");
|
|
1576
|
+
setProperty(region, "background-color", SCREENSHOT_BLOCK_BACKGROUND);
|
|
1577
|
+
setProperty(region, "background-image", labeled ? MASK_LABEL_IMAGE : "none");
|
|
1578
|
+
if (labeled) {
|
|
1579
|
+
setProperty(region, "background-repeat", "no-repeat");
|
|
1580
|
+
setProperty(region, "background-position", "center");
|
|
1581
|
+
setProperty(region, "background-size", "auto");
|
|
1582
|
+
}
|
|
1583
|
+
TEXT_HIDING_PROPERTIES.forEach(([name, value]) => setProperty(region, name, value));
|
|
1584
|
+
setProperty(region, "pointer-events", "none");
|
|
1585
|
+
forEachElementDeep(region, (descendant) => {
|
|
1586
|
+
if (descendant !== region) {
|
|
1587
|
+
setProperty(descendant, "visibility", "hidden");
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
function coverPrivateRegions(root, setProperty) {
|
|
1592
|
+
const blocked = [];
|
|
1593
|
+
const masked = [];
|
|
1594
|
+
forEachElementDeep(root, (element) => {
|
|
1595
|
+
if (matchesSafely(element, SCREENSHOT_BLOCK_SELECTOR)) {
|
|
1596
|
+
blocked.push(element);
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (matchesSafely(element, SCREENSHOT_FULL_MASK_SELECTOR) && isElementFullyMasked(element)) {
|
|
1600
|
+
masked.push(element);
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
masked.forEach((region) => coverMaskedRegion(region, setProperty));
|
|
1604
|
+
blocked.forEach((region) => coverBlockedRegion(region, setProperty));
|
|
1605
|
+
}
|
|
1606
|
+
function applyScreenshotPrivacyMask(clonedRoot) {
|
|
1607
|
+
coverPrivateRegions(clonedRoot, overwriteProperty);
|
|
1608
|
+
const walker = clonedRoot.ownerDocument.createTreeWalker(clonedRoot, NodeFilter.SHOW_TEXT);
|
|
1609
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
1610
|
+
const text = node.nodeValue;
|
|
1611
|
+
if (!text) continue;
|
|
1612
|
+
node.nodeValue = redactScreenshotText(text);
|
|
1613
|
+
}
|
|
1614
|
+
clonedRoot.querySelectorAll(VALUE_ELEMENT_SELECTOR).forEach((element) => {
|
|
1615
|
+
const value = element.getAttribute("value");
|
|
1616
|
+
if (!value) return;
|
|
1617
|
+
const hidden = closestSafely(element, SCREENSHOT_BLOCK_SELECTOR) !== null || isElementFullyMasked(element) || hasSensitiveValueHint(element);
|
|
1618
|
+
element.setAttribute("value", hidden ? "" : redactScreenshotText(value));
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1353
1621
|
const SCREENSHOT_DATA_URL_QUALITY = 0.95;
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const
|
|
1622
|
+
let nextCaptureRunId = 0;
|
|
1623
|
+
function createCaptureAttributeNames() {
|
|
1624
|
+
const runId = ++nextCaptureRunId;
|
|
1625
|
+
return {
|
|
1626
|
+
excludeNodeId: `data-issue-sticker-capture-exclude-node-id-${runId}`,
|
|
1627
|
+
stickyNodeId: `data-issue-sticker-modern-sticky-node-id-${runId}`,
|
|
1628
|
+
scrollAncestorId: `data-issue-sticker-modern-scroll-ancestor-id-${runId}`
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1357
1631
|
let modernScreenshotModule = null;
|
|
1358
1632
|
function loadModernScreenshot() {
|
|
1359
1633
|
if (!modernScreenshotModule) {
|
|
@@ -1378,17 +1652,6 @@ async function waitForDocumentFonts() {
|
|
|
1378
1652
|
}
|
|
1379
1653
|
await fontFaceSet.ready;
|
|
1380
1654
|
}
|
|
1381
|
-
function forEachElementDeep(root, callback) {
|
|
1382
|
-
if (root instanceof Element) {
|
|
1383
|
-
callback(root);
|
|
1384
|
-
if (root.shadowRoot) {
|
|
1385
|
-
forEachElementDeep(root.shadowRoot, callback);
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
Array.from(root.children).forEach((child) => {
|
|
1389
|
-
forEachElementDeep(child, callback);
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
1655
|
function isScrollableOnAxis(element, axis) {
|
|
1393
1656
|
const style = getComputedStyle(element);
|
|
1394
1657
|
const overflowValue = axis === "y" ? style.overflowY || style.overflow : style.overflowX || style.overflow;
|
|
@@ -1412,28 +1675,27 @@ function parseStickyInset(value) {
|
|
|
1412
1675
|
const parsed = Number.parseFloat(value);
|
|
1413
1676
|
return Number.isFinite(parsed) ? parsed : null;
|
|
1414
1677
|
}
|
|
1415
|
-
function createExcludeElementSnapshot(root, excludeSelectors) {
|
|
1678
|
+
function createExcludeElementSnapshot(root, excludeSelectors, attributeNames) {
|
|
1416
1679
|
if (excludeSelectors.length === 0) {
|
|
1417
1680
|
return {
|
|
1418
1681
|
applyToClone: () => void 0,
|
|
1419
1682
|
cleanup: () => void 0
|
|
1420
1683
|
};
|
|
1421
1684
|
}
|
|
1685
|
+
const { excludeNodeId: excludeAttribute } = attributeNames;
|
|
1422
1686
|
const markedElements = [];
|
|
1423
1687
|
let nextCaptureId = 0;
|
|
1424
1688
|
forEachElementDeep(root, (element) => {
|
|
1425
1689
|
if (!excludeSelectors.some((selector) => element.matches(selector))) {
|
|
1426
1690
|
return;
|
|
1427
1691
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
element.setAttribute(CAPTURE_EXCLUDE_NODE_ID_ATTRIBUTE, captureId);
|
|
1431
|
-
markedElements.push({ element, previousValue });
|
|
1692
|
+
element.setAttribute(excludeAttribute, String(++nextCaptureId));
|
|
1693
|
+
markedElements.push(element);
|
|
1432
1694
|
});
|
|
1433
1695
|
return {
|
|
1434
1696
|
applyToClone(clonedRoot) {
|
|
1435
1697
|
forEachElementDeep(clonedRoot, (element) => {
|
|
1436
|
-
if (!element.hasAttribute(
|
|
1698
|
+
if (!element.hasAttribute(excludeAttribute)) {
|
|
1437
1699
|
return;
|
|
1438
1700
|
}
|
|
1439
1701
|
const styledElement = element;
|
|
@@ -1442,35 +1704,29 @@ function createExcludeElementSnapshot(root, excludeSelectors) {
|
|
|
1442
1704
|
styledElement.style.setProperty("visibility", "hidden", "important");
|
|
1443
1705
|
styledElement.style.setProperty("pointer-events", "none", "important");
|
|
1444
1706
|
}
|
|
1445
|
-
element.removeAttribute(
|
|
1707
|
+
element.removeAttribute(excludeAttribute);
|
|
1446
1708
|
});
|
|
1447
1709
|
},
|
|
1448
1710
|
cleanup() {
|
|
1449
|
-
markedElements.forEach((
|
|
1450
|
-
if (previousValue === null) {
|
|
1451
|
-
element.removeAttribute(CAPTURE_EXCLUDE_NODE_ID_ATTRIBUTE);
|
|
1452
|
-
return;
|
|
1453
|
-
}
|
|
1454
|
-
element.setAttribute(CAPTURE_EXCLUDE_NODE_ID_ATTRIBUTE, previousValue);
|
|
1455
|
-
});
|
|
1711
|
+
markedElements.forEach((element) => element.removeAttribute(excludeAttribute));
|
|
1456
1712
|
}
|
|
1457
1713
|
};
|
|
1458
1714
|
}
|
|
1459
|
-
function createModernStickySnapshot(root) {
|
|
1715
|
+
function createModernStickySnapshot(root, attributeNames) {
|
|
1716
|
+
const { stickyNodeId: stickyAttribute, scrollAncestorId: scrollAncestorAttribute } = attributeNames;
|
|
1460
1717
|
const stickyOverlays = /* @__PURE__ */ new Map();
|
|
1461
1718
|
const markedStickyElements = [];
|
|
1462
1719
|
const markedScrollAncestors = [];
|
|
1463
1720
|
let nextStickyId = 0;
|
|
1464
1721
|
let nextScrollAncestorId = 0;
|
|
1465
1722
|
function ensureScrollAncestorId(element) {
|
|
1466
|
-
const existingId = element.getAttribute(
|
|
1723
|
+
const existingId = element.getAttribute(scrollAncestorAttribute);
|
|
1467
1724
|
if (existingId) {
|
|
1468
1725
|
return existingId;
|
|
1469
1726
|
}
|
|
1470
1727
|
const ancestorId = `scroll-${++nextScrollAncestorId}`;
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
markedScrollAncestors.push({ element, previousValue });
|
|
1728
|
+
element.setAttribute(scrollAncestorAttribute, ancestorId);
|
|
1729
|
+
markedScrollAncestors.push(element);
|
|
1474
1730
|
return ancestorId;
|
|
1475
1731
|
}
|
|
1476
1732
|
forEachElementDeep(root, (node) => {
|
|
@@ -1497,7 +1753,6 @@ function createModernStickySnapshot(root) {
|
|
|
1497
1753
|
return;
|
|
1498
1754
|
}
|
|
1499
1755
|
const captureId = String(++nextStickyId);
|
|
1500
|
-
const previousValue = node.getAttribute(MODERN_STICKY_NODE_ID_ATTRIBUTE);
|
|
1501
1756
|
const ancestorId = ensureScrollAncestorId(scrollAncestor);
|
|
1502
1757
|
stickyOverlays.set(captureId, {
|
|
1503
1758
|
ancestorId,
|
|
@@ -1506,8 +1761,8 @@ function createModernStickySnapshot(root) {
|
|
|
1506
1761
|
width: nodeRect.width,
|
|
1507
1762
|
height: nodeRect.height
|
|
1508
1763
|
});
|
|
1509
|
-
node.setAttribute(
|
|
1510
|
-
markedStickyElements.push(
|
|
1764
|
+
node.setAttribute(stickyAttribute, captureId);
|
|
1765
|
+
markedStickyElements.push(node);
|
|
1511
1766
|
});
|
|
1512
1767
|
return {
|
|
1513
1768
|
applyToClone(clonedRoot) {
|
|
@@ -1517,11 +1772,11 @@ function createModernStickySnapshot(root) {
|
|
|
1517
1772
|
if (!(node instanceof HTMLElement)) {
|
|
1518
1773
|
return;
|
|
1519
1774
|
}
|
|
1520
|
-
const captureId = node.getAttribute(
|
|
1775
|
+
const captureId = node.getAttribute(stickyAttribute);
|
|
1521
1776
|
if (captureId) {
|
|
1522
1777
|
stickyById.set(captureId, node);
|
|
1523
1778
|
}
|
|
1524
|
-
const scrollAncestorId = node.getAttribute(
|
|
1779
|
+
const scrollAncestorId = node.getAttribute(scrollAncestorAttribute);
|
|
1525
1780
|
if (scrollAncestorId) {
|
|
1526
1781
|
scrollAncestorById.set(scrollAncestorId, node);
|
|
1527
1782
|
}
|
|
@@ -1536,8 +1791,8 @@ function createModernStickySnapshot(root) {
|
|
|
1536
1791
|
if (!(overlay instanceof HTMLElement)) {
|
|
1537
1792
|
return;
|
|
1538
1793
|
}
|
|
1539
|
-
overlay.removeAttribute(
|
|
1540
|
-
overlay.removeAttribute(
|
|
1794
|
+
overlay.removeAttribute(stickyAttribute);
|
|
1795
|
+
overlay.removeAttribute(scrollAncestorAttribute);
|
|
1541
1796
|
overlay.style.position = "absolute";
|
|
1542
1797
|
overlay.style.top = `${top}px`;
|
|
1543
1798
|
overlay.style.left = `${left}px`;
|
|
@@ -1563,36 +1818,34 @@ function createModernStickySnapshot(root) {
|
|
|
1563
1818
|
if (!(node instanceof HTMLElement)) {
|
|
1564
1819
|
return;
|
|
1565
1820
|
}
|
|
1566
|
-
node.removeAttribute(
|
|
1567
|
-
node.removeAttribute(
|
|
1821
|
+
node.removeAttribute(stickyAttribute);
|
|
1822
|
+
node.removeAttribute(scrollAncestorAttribute);
|
|
1568
1823
|
});
|
|
1569
1824
|
},
|
|
1570
1825
|
cleanup() {
|
|
1571
|
-
markedStickyElements.forEach((
|
|
1572
|
-
|
|
1573
|
-
element.removeAttribute(MODERN_STICKY_NODE_ID_ATTRIBUTE);
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
|
-
element.setAttribute(MODERN_STICKY_NODE_ID_ATTRIBUTE, previousValue);
|
|
1577
|
-
});
|
|
1578
|
-
markedScrollAncestors.forEach(({ element, previousValue }) => {
|
|
1579
|
-
if (previousValue === null) {
|
|
1580
|
-
element.removeAttribute(MODERN_SCROLL_ANCESTOR_ID_ATTRIBUTE);
|
|
1581
|
-
return;
|
|
1582
|
-
}
|
|
1583
|
-
element.setAttribute(MODERN_SCROLL_ANCESTOR_ID_ATTRIBUTE, previousValue);
|
|
1584
|
-
});
|
|
1826
|
+
markedStickyElements.forEach((element) => element.removeAttribute(stickyAttribute));
|
|
1827
|
+
markedScrollAncestors.forEach((element) => element.removeAttribute(scrollAncestorAttribute));
|
|
1585
1828
|
}
|
|
1586
1829
|
};
|
|
1587
1830
|
}
|
|
1831
|
+
function blobToDataUrl(blob) {
|
|
1832
|
+
return new Promise((resolve, reject) => {
|
|
1833
|
+
const reader = new FileReader();
|
|
1834
|
+
reader.onload = () => resolve(String(reader.result));
|
|
1835
|
+
reader.onerror = () => reject(reader.error ?? new Error("스크린샷을 dataUrl 로 변환하지 못했습니다."));
|
|
1836
|
+
reader.readAsDataURL(blob);
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1588
1839
|
async function captureWithModernScreenshot(options) {
|
|
1589
|
-
const {
|
|
1840
|
+
const { domToBlob } = await loadModernScreenshot();
|
|
1590
1841
|
const { element, excludeSelectors = [], width, height, scale = getCaptureScale() } = options;
|
|
1591
1842
|
await waitForDocumentFonts();
|
|
1592
|
-
const
|
|
1593
|
-
const
|
|
1843
|
+
const attributeNames = createCaptureAttributeNames();
|
|
1844
|
+
const stickySnapshot = createModernStickySnapshot(element, attributeNames);
|
|
1845
|
+
const excludeSnapshot = createExcludeElementSnapshot(element, excludeSelectors, attributeNames);
|
|
1594
1846
|
try {
|
|
1595
1847
|
const captureOptions = {
|
|
1848
|
+
type: "image/webp",
|
|
1596
1849
|
scale,
|
|
1597
1850
|
quality: SCREENSHOT_DATA_URL_QUALITY,
|
|
1598
1851
|
features: {
|
|
@@ -1604,6 +1857,7 @@ async function captureWithModernScreenshot(options) {
|
|
|
1604
1857
|
}
|
|
1605
1858
|
stickySnapshot.applyToClone(cloned);
|
|
1606
1859
|
excludeSnapshot.applyToClone(cloned);
|
|
1860
|
+
applyScreenshotPrivacyMask(cloned);
|
|
1607
1861
|
}
|
|
1608
1862
|
};
|
|
1609
1863
|
if (width) {
|
|
@@ -1612,12 +1866,53 @@ async function captureWithModernScreenshot(options) {
|
|
|
1612
1866
|
if (height) {
|
|
1613
1867
|
captureOptions.height = height;
|
|
1614
1868
|
}
|
|
1615
|
-
return await
|
|
1869
|
+
return await blobToDataUrl(await domToBlob(element, captureOptions));
|
|
1616
1870
|
} finally {
|
|
1617
1871
|
excludeSnapshot.cleanup();
|
|
1618
1872
|
stickySnapshot.cleanup();
|
|
1619
1873
|
}
|
|
1620
1874
|
}
|
|
1875
|
+
const ISSUE_STICKER_INTERNAL_LOG_PREFIX = "__ISSUE_STICKER_INTERNAL_DEBUG__";
|
|
1876
|
+
function isInternalDebugLog$1(message2) {
|
|
1877
|
+
return Boolean(message2 == null ? void 0 : message2.includes(ISSUE_STICKER_INTERNAL_LOG_PREFIX));
|
|
1878
|
+
}
|
|
1879
|
+
function isIssueStickerInternalConsoleLog$1(log) {
|
|
1880
|
+
return isInternalDebugLog$1(log.message);
|
|
1881
|
+
}
|
|
1882
|
+
const __vite_import_meta_env__ = { "DEV": false };
|
|
1883
|
+
function isDevLoggingEnabled() {
|
|
1884
|
+
const env = __vite_import_meta_env__;
|
|
1885
|
+
{
|
|
1886
|
+
return env.DEV;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
function isInternalDebugLog(message2) {
|
|
1890
|
+
return Boolean(message2 == null ? void 0 : message2.includes(ISSUE_STICKER_INTERNAL_LOG_PREFIX));
|
|
1891
|
+
}
|
|
1892
|
+
function write(method, scope, args) {
|
|
1893
|
+
if (!isDevLoggingEnabled()) {
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
const log = console[method];
|
|
1897
|
+
log(ISSUE_STICKER_INTERNAL_LOG_PREFIX, `[${scope}]`, ...args);
|
|
1898
|
+
}
|
|
1899
|
+
const devLogger = {
|
|
1900
|
+
log(scope, ...args) {
|
|
1901
|
+
write("log", scope, args);
|
|
1902
|
+
},
|
|
1903
|
+
info(scope, ...args) {
|
|
1904
|
+
write("info", scope, args);
|
|
1905
|
+
},
|
|
1906
|
+
warn(scope, ...args) {
|
|
1907
|
+
write("warn", scope, args);
|
|
1908
|
+
},
|
|
1909
|
+
error(scope, ...args) {
|
|
1910
|
+
write("error", scope, args);
|
|
1911
|
+
},
|
|
1912
|
+
debug(scope, ...args) {
|
|
1913
|
+
write("debug", scope, args);
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1621
1916
|
class DirectUploadError extends Error {
|
|
1622
1917
|
constructor(message2, status, data) {
|
|
1623
1918
|
super(message2);
|
|
@@ -3515,13 +3810,6 @@ async function uploadScreenshotDataUrls(screenshotDataUrls, uploadSignedMedia, i
|
|
|
3515
3810
|
}
|
|
3516
3811
|
throw new Error("스크린샷 업로드 응답에 URL이 없습니다.");
|
|
3517
3812
|
}
|
|
3518
|
-
const ISSUE_STICKER_INTERNAL_LOG_PREFIX = "__ISSUE_STICKER_INTERNAL_DEBUG__";
|
|
3519
|
-
function isInternalDebugLog$1(message2) {
|
|
3520
|
-
return Boolean(message2 == null ? void 0 : message2.includes(ISSUE_STICKER_INTERNAL_LOG_PREFIX));
|
|
3521
|
-
}
|
|
3522
|
-
function isIssueStickerInternalConsoleLog$1(log) {
|
|
3523
|
-
return isInternalDebugLog$1(log.message);
|
|
3524
|
-
}
|
|
3525
3813
|
function getCurrentPageUrl() {
|
|
3526
3814
|
if (typeof window === "undefined") {
|
|
3527
3815
|
return "";
|
|
@@ -13477,40 +13765,6 @@ function buildIssueIntegrationsPayload({
|
|
|
13477
13765
|
}
|
|
13478
13766
|
return payload.jira || payload.notion ? payload : void 0;
|
|
13479
13767
|
}
|
|
13480
|
-
const __vite_import_meta_env__ = { "DEV": false };
|
|
13481
|
-
function isDevLoggingEnabled() {
|
|
13482
|
-
const env = __vite_import_meta_env__;
|
|
13483
|
-
{
|
|
13484
|
-
return env.DEV;
|
|
13485
|
-
}
|
|
13486
|
-
}
|
|
13487
|
-
function isInternalDebugLog(message2) {
|
|
13488
|
-
return Boolean(message2 == null ? void 0 : message2.includes(ISSUE_STICKER_INTERNAL_LOG_PREFIX));
|
|
13489
|
-
}
|
|
13490
|
-
function write(method, scope, args) {
|
|
13491
|
-
if (!isDevLoggingEnabled()) {
|
|
13492
|
-
return;
|
|
13493
|
-
}
|
|
13494
|
-
const log = console[method];
|
|
13495
|
-
log(ISSUE_STICKER_INTERNAL_LOG_PREFIX, `[${scope}]`, ...args);
|
|
13496
|
-
}
|
|
13497
|
-
const devLogger = {
|
|
13498
|
-
log(scope, ...args) {
|
|
13499
|
-
write("log", scope, args);
|
|
13500
|
-
},
|
|
13501
|
-
info(scope, ...args) {
|
|
13502
|
-
write("info", scope, args);
|
|
13503
|
-
},
|
|
13504
|
-
warn(scope, ...args) {
|
|
13505
|
-
write("warn", scope, args);
|
|
13506
|
-
},
|
|
13507
|
-
error(scope, ...args) {
|
|
13508
|
-
write("error", scope, args);
|
|
13509
|
-
},
|
|
13510
|
-
debug(scope, ...args) {
|
|
13511
|
-
write("debug", scope, args);
|
|
13512
|
-
}
|
|
13513
|
-
};
|
|
13514
13768
|
function buildGuestOwnerQuery(mode, externalUserId) {
|
|
13515
13769
|
if (mode !== "public") return "";
|
|
13516
13770
|
if (!externalUserId) return "";
|
|
@@ -13636,65 +13890,66 @@ function buildExternalUserPayload(user) {
|
|
|
13636
13890
|
};
|
|
13637
13891
|
}
|
|
13638
13892
|
export {
|
|
13639
|
-
|
|
13893
|
+
X as $,
|
|
13640
13894
|
trimLogBackupPayload as A,
|
|
13641
13895
|
createSafeLogBackup as B,
|
|
13642
13896
|
ConsoleCollector as C,
|
|
13643
13897
|
getLogBackupSessionId as D,
|
|
13644
13898
|
createIndexedDbLogBackup as E,
|
|
13645
13899
|
PopoverTrigger as F,
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13900
|
+
Input as G,
|
|
13901
|
+
PopoverContent as H,
|
|
13902
|
+
ISSUE_STICKER_INTERNAL_LOG_PREFIX as I,
|
|
13903
|
+
Select$1 as J,
|
|
13904
|
+
SelectTrigger as K,
|
|
13651
13905
|
Label as L,
|
|
13652
|
-
|
|
13906
|
+
SelectValue as M,
|
|
13653
13907
|
NetworkCollector as N,
|
|
13654
|
-
|
|
13908
|
+
SelectContent as O,
|
|
13655
13909
|
Popover as P,
|
|
13656
|
-
|
|
13657
|
-
|
|
13910
|
+
SelectItem as Q,
|
|
13911
|
+
getJiraMetadata as R,
|
|
13658
13912
|
ScreenRecordingController as S,
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13913
|
+
buildJiraIssueFields as T,
|
|
13914
|
+
Button$1 as U,
|
|
13915
|
+
Root2 as V,
|
|
13916
|
+
Trigger as W,
|
|
13917
|
+
ChevronDown as X,
|
|
13918
|
+
Portal as Y,
|
|
13919
|
+
Content2 as Z,
|
|
13920
|
+
Check as _,
|
|
13667
13921
|
uploadSignedMediaWithApi as a,
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13922
|
+
DatePicker as a0,
|
|
13923
|
+
getNotionPageMetadata as a1,
|
|
13924
|
+
buildNotionFieldViews as a2,
|
|
13925
|
+
DirectUploadError as a3,
|
|
13926
|
+
toast as a4,
|
|
13673
13927
|
getSnapshot as a5,
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13928
|
+
subscribe as a6,
|
|
13929
|
+
getRegisteredUploadId as a7,
|
|
13930
|
+
ChevronRight as a8,
|
|
13931
|
+
ReactRemoveScroll as a9,
|
|
13932
|
+
hideOthers as aa,
|
|
13933
|
+
useFocusGuards as ab,
|
|
13934
|
+
FocusScope as ac,
|
|
13935
|
+
getExposedJiraFields as ad,
|
|
13936
|
+
isJiraFieldExposed as ae,
|
|
13937
|
+
getPrimaryJiraMapping as af,
|
|
13938
|
+
createCollection as ag,
|
|
13939
|
+
useDirection as ah,
|
|
13940
|
+
getPrimaryNotionMapping as ai,
|
|
13941
|
+
buttonVariants as aj,
|
|
13942
|
+
findElementBySelector as ak,
|
|
13943
|
+
findElementByXPath as al,
|
|
13944
|
+
OnboardingProvider as am,
|
|
13945
|
+
useOnboardingTarget as an,
|
|
13946
|
+
useOnboardingFlow as ao,
|
|
13947
|
+
ISSUE_STICKER_HOST_ELEMENT_ID as ap,
|
|
13948
|
+
getIssueStickerRuntimeOwner as aq,
|
|
13949
|
+
ISSUE_STICKER_RUNTIME_OWNER as ar,
|
|
13950
|
+
createRuntimeHostElement as as,
|
|
13951
|
+
attachHostTypingGuard as at,
|
|
13952
|
+
ISSUE_STICKER_EXTENSION_RUNTIME_READY_EVENT as au,
|
|
13698
13953
|
normalizeJiraFieldId as b,
|
|
13699
13954
|
captureWithModernScreenshot as c,
|
|
13700
13955
|
directUploadToSignedUrl as d,
|