issue-sticker 0.11.0 → 0.13.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 CHANGED
@@ -2,6 +2,95 @@
2
2
 
3
3
  npm 패키지 `issue-sticker`의 변경 이력입니다. 설치·업그레이드에 영향을 주는 변경만 기록합니다.
4
4
 
5
+ ## 0.13.0 - 2026-11-03
6
+
7
+ **백엔드 1.14.0 이상이 필요합니다.** 프로젝트 마스킹 정책(`GET /api/sdk/masking-policy`, `409 MASKING_POLICY_CHANGED`)과 설명 다시 불러오기(`POST /api/sdk/issues/:id/description/refresh`, 설명 숨김 저장 필드)를 사용합니다. 정책을 적용할 수 없는 상태에서는 이슈를 만들지 않습니다.
8
+
9
+ ### 호환성이 깨지는 변경 (headless)
10
+
11
+ - `HeadlessErrorCode` 에 `MASKING_POLICY_UNAVAILABLE`·`MASKING_POLICY_CHANGED`·`MASKING_SELECTOR_UNSUPPORTED`·`RATE_LIMITED` 를 추가합니다. 코드 값을 빠짐없이 나열해 분기하는 코드(`switch` 와 `never` 검사)나 `Record<HeadlessErrorCode, …>` 맵은 네 값을 처리해야 컴파일됩니다.
12
+ - 화면 마스킹 규칙의 선택자를 브라우저에서 적용할 수 없으면 `submitDraft()`·`createIssue()` 모두 `CAPTURE_FAILED` 대신 `MASKING_SELECTOR_UNSUPPORTED` 로 실패합니다. 다시 시도해도 결과가 같으므로 워크스페이스 관리자에게 문의하도록 안내합니다.
13
+ - 멤버로 로그인하지 않은 상태에서 서버가 401 을 돌려주면 `MEMBER_AUTH_REQUIRED` 대신 `AUTH_FAILED` 로 실패합니다. API key 문제를 멤버 로그인 문제로 안내하던 것을 바로잡습니다. 멤버 로그인 상태의 401 은 그대로 `MEMBER_AUTH_REQUIRED` 입니다.
14
+
15
+ ### 추가
16
+
17
+ - 위젯이 초기화할 때 API 키에 연결된 프로젝트의 마스킹 정책을 받아 메모리에 둡니다. 다른 키로 다시 초기화하면 앞 프로젝트의 정책은 버립니다. API 키에 `issues:create` 권한이 없으면 정책을 받을 수 없고, 정책을 적용할 수 없는 상태에서는 이슈를 만들지 않습니다.
18
+ - 이슈를 제출할 때 프로젝트 마스킹 정책을 콘솔·네트워크 로그, 웹소켓 기록, 페이지 URL 에 적용합니다. 키 이름 규칙으로 가리지 못한 키가 남은 네트워크 본문은 첨부에서 뺍니다.
19
+ - 마스킹 정책의 화면 요소 규칙을 세션 리플레이에도 적용합니다. 규칙에 해당하는 요소는 같은 크기의 가려짐 상자로 바뀌어 전송됩니다. 리플레이에 정책을 적용하지 못하면 위젯은 이슈를 생성하지 않고 안내하며, headless `submitDraft()` 는 `CAPTURE_FAILED` 로 실패합니다.
20
+ - 제출 직전에 정책을 다시 확인합니다. 서버가 `409 MASKING_POLICY_CHANGED` 로 정책이 바뀌었다고 알리면, 화면 마스킹 규칙이 같을 때는 새 정책으로 한 번 다시 제출하고 바뀌었을 때는 이슈를 생성하지 않고 안내합니다.
21
+ - 정책이 화면 녹화를 금지하면 영상 없이 이슈를 생성합니다. 위젯은 완료 안내에 이를 덧붙이고, headless `submitDraft()` 는 반환값에 `videoExcluded: true` 를 함께 돌려줍니다.
22
+ - 영상을 업로드하는 동안 프로젝트 마스킹 정책이 화면 녹화를 막으면 위젯이 "영상을 업로드하지 못했습니다" 대신 마스킹 정책 때문에 영상을 첨부하지 않았다고 안내합니다. 이슈는 영상 없이 남습니다. headless 는 이 경우 `snapshot.issues`·`snapshot.activeIssue` 의 이슈에 `video_status: 'failed'` 와 함께 `video_failure_reason: 'masking_video_excluded'` 를 싣습니다. 새 필드는 선택 필드라 기존 코드는 그대로 동작합니다.
23
+ - 마스킹 정책을 적용하지 못해 스크린샷을 첨부하지 않으면 이슈 설명 끝에 안내를 추가합니다. 요소 스크린샷처럼 남은 스크린샷을 첨부했으면 일부만 첨부하지 않았다고 안내합니다. AI 작성(`intent`)으로 제출하면 서버가 설명을 새로 생성하면서 이 안내가 사라지므로, headless `submitDraft()`·`createIssue()` 는 반환값에 `screenshotExcluded: true` 를 함께 돌려줍니다.
24
+ - headless `createIssue()` 입력에 `onError` 를 추가합니다. 이슈를 생성하지 않고 `null` 로 끝날 때 한 번 호출되며, `submitDraft()` 가 던지는 것과 같은 코드의 `IssueStickerHeadlessError` 를 전달합니다. 앱은 이 코드를 보고 다시 시도할지 판단합니다.
25
+ - 입력이 비었으면 `VALIDATION_ERROR`, 60초에 5건인 호출 한도를 넘었으면 `RATE_LIMITED` 로 전달합니다. 마스킹 정책 실패는 `MASKING_POLICY_CHANGED`·`MASKING_POLICY_UNAVAILABLE`·`CAPTURE_FAILED`·`MASKING_SELECTOR_UNSUPPORTED` 로 전달합니다.
26
+ - `onError` 에서 예외가 발생해도 `createIssue()` 는 예외를 던지지 않고 `null` 을 돌려줍니다.
27
+ - `createIssue()` 를 입력 없이 호출해도 예외를 던지지 않고 `VALIDATION_ERROR` 로 끝납니다. 이슈를 생성한 뒤 이후 처리에서 예외가 발생하면 `onError` 를 호출하지 않고 생성한 이슈를 돌려줍니다.
28
+ - 이슈 설명에 Jira에서만 고칠 수 있는 요소(패널, 접기 블록, 첨부 등)가 있으면 어떤 요소인지 안내합니다. 안내가 있어도 나머지 설명은 이슈스티커에서 계속 수정할 수 있고, 해당 요소를 바꾸거나 지우면 저장되지 않으며 되돌린 뒤 다시 저장하면 됩니다.
29
+ - 설명 저장이 실패하면 원인에 맞는 안내 문구를 보여줍니다. 연동된 서비스에서 설명이 먼저 바뀐 경우에는 최신 내용을 불러오고, 입력하던 내용은 그대로 둡니다.
30
+
31
+ ### 개선
32
+
33
+ - Notion과 연결된 이슈의 설명도 이슈스티커에서 수정할 수 있습니다. 이미지·파일·콜아웃·북마크처럼 Notion에서만 고칠 수 있는 요소가 있으면 어떤 요소인지 안내하고, 나머지 설명은 계속 수정할 수 있습니다. 설명 섹션의 제목이 Notion에서 지워진 경우에만 수정 버튼 대신 잠금 안내를 보여줍니다.
34
+ - 위젯에서 Jira·Notion과 연결된 이슈의 설명에 있는 패널, 콜아웃, 멘션처럼 외부 서비스에서만 수정할 수 있는 내용을 읽기 전용으로 표시합니다. 수정 화면에서는 이 내용을 숨기고, 저장해도 Jira·Notion 원본의 같은 자리에 그대로 남습니다. 첨부 이미지·파일처럼 보여줄 수 없는 내용은 한 줄 안내로 대신합니다. 설명 전체가 이런 내용이면 수정 버튼 없이 안내만 표시합니다.
35
+ - 이전에 연결된 이슈 중 외부 서비스에서만 수정할 수 있는 내용이 든 이슈는 설명을 다시 불러와야 수정할 수 있습니다. 이런 이슈에는 수정 버튼 대신 「다시 불러오기」가 표시되고, 이 버튼을 클릭하면 이슈 설명이 Jira·Notion의 현재 설명으로 바뀝니다. 연결이 끊겼거나 Jira 이슈·Notion 페이지가 삭제되어 다시 불러올 수 없는 이슈, 다시 불러와도 숨길 내용을 찾지 못한 이슈는 이전처럼 전체 설명을 수정합니다.
36
+
37
+ ### 개인정보 보호
38
+
39
+ - `rr-block` 등 차단 표식이 붙은 영역 안의 캔버스 이미지와 조작 기록을 세션 리플레이에 포함하지 않습니다. 이전에는 차단 영역이어도 캔버스를 조작하면 그 시점의 캔버스 이미지와 3D 오브젝트 이름이 리플레이에 첨부되었습니다. shadow root 안의 캔버스도 host 요소가 차단 영역 안에 있으면 포함하지 않습니다.
40
+ - `rr-mask` 등 마스킹 표식이 붙은 요소 안에 shadow root 가 있으면, 그 안의 텍스트도 세션 리플레이에서 가립니다. 이전에는 shadow root 안의 텍스트가 그대로 남았습니다. 마스킹 영역 안의 shadow root 에 있는 캔버스도 리플레이에 이미지와 조작 기록을 포함하지 않습니다.
41
+ - 화면 요소 마스킹 규칙으로 가린 영역의 입력창이나 캔버스가 페이지에서 제거된 뒤 페이지 스크립트가 값을 바꾸거나 그리면, 그 내용이 세션 리플레이에 남을 수 있던 문제를 수정합니다. 색·범위 입력값과 체크 상태, 캔버스 그리기 기록이 해당합니다. 이제 이슈를 생성할 때 리플레이 화면에 없는 요소의 입력·캔버스 기록을 지웁니다.
42
+ - 마스킹 정책으로 가린 영역 위의 클릭 좌표와 마우스 이동 위치는 세션 리플레이에 그대로 남깁니다. 이벤트 대상은 가려짐 상자로 바뀌어, 가린 요소 안의 어떤 요소를 클릭했는지는 전송하지 않습니다. 화면 키패드처럼 클릭 위치가 곧 입력값인 영역은 리플레이에서 입력값이 드러날 수 있습니다.
43
+
44
+ ### 수정
45
+
46
+ - 세션 리플레이에 열린 shadow root 안의 캔버스(`<model-viewer>` 등)를 조작한 기록과 캔버스 이미지가 포함됩니다. 이전에는 이런 캔버스의 조작을 기록하지 않았습니다.
47
+ - 캡처 제외로 지정한 canvas, video, 같은 출처 iframe이 스크린샷에 그대로 찍히던 문제를 수정했습니다. 이제 다른 제외 요소처럼 감춰지고, 주변 요소의 배치는 그대로 유지됩니다.
48
+ - 한 페이지를 오래 사용하는 웹앱에서 세션 리플레이를 녹화할수록 메모리 사용량이 계속 늘던 문제를 수정합니다. 화면 요소 마스킹 규칙에 해당하는 요소가 계속 생기고 사라지면 30분에 13MB 가까이 늘었습니다. 이제 리플레이 기록 구간(3분 안팎)에 나온 요소의 가림 정보만 유지하고, 리플레이 백업 크기 상한에 가림 정보도 포함합니다. 페이지를 이동한 뒤 이전 페이지의 리플레이를 복원할 때, 가림 정보가 이미 정리된 구간은 리플레이에서 뺍니다.
49
+ - 마스킹 정책을 받기 전에 찍은 스크린샷으로 이슈를 제출하면, 정책이 바뀌지 않았는데도 "마스킹 정책을 적용하기 위해 스크린샷을 다시 캡처했습니다" 안내가 뜨던 문제를 수정합니다. 이제 제출할 때 받은 정책으로 스크린샷을 한 번 다시 찍어 가린 뒤 안내 없이 이슈를 생성합니다. 세션 리플레이가 정책 없이 녹화된 경우는 기존처럼 안내하고 녹화를 새로 시작합니다.
50
+
51
+ ## 0.12.0 - 2026-10-14
52
+
53
+ **백엔드 1.13.0 이상이 필요합니다.** 비동기 업로드(`video_status`·`resumableUrl`·`replay_status`·`replayMeta` 계약)와 `Retry-After` 헤더 노출을 사용합니다.
54
+
55
+ ### 호환성이 깨지는 변경 (headless)
56
+
57
+ - `submitDraft()` 는 영상 업로드를 기다리지 않고 이슈 생성 직후 결과를 돌려줍니다. 영상 이슈의 `video` 는 `null`, `video_status` 는 `'uploading'` 입니다.
58
+ - 마이그레이션: `submitDraft()` 의 반환값에서 `video` 를 바로 읽던 코드는 `snapshot.issues` 에서 같은 이슈의 `video_status` 가 `'ready'` 가 된 뒤 `openIssue(issueId)` 로 이슈를 열어 `snapshot.activeIssue.video` 에서 읽어주세요. `refreshIssues()` 가 받는 스티커 목록에는 영상 URL 이 없습니다. `config.user` 가 없는 게스트는 이슈를 다시 조회할 수 없어 영상 URL 을 받을 수 없습니다. 업로드 실패 안내가 필요하면 `snapshot.videoUploads` 의 `status: 'failed'` 를 보고 `retryVideoUpload(issueId)` 를 호출합니다.
59
+ - `submitDraft()`·`createIssue()` 는 세션 리플레이·웹소켓 로그 업로드를 기다리지 않습니다. 리플레이가 있는 이슈의 `replay_status` 는 `'uploading'` 으로 시작해 업로드가 끝나면 `snapshot.issues` 에서 `'ready'` 로 바뀝니다. 진행은 `snapshot.attachmentUploads` 로 확인합니다.
60
+ - 마이그레이션: 이슈 생성 직후 리플레이를 조회하던 코드는 `replay_status` 가 `'ready'` 가 된 뒤 `openIssue(issueId)` 로 다시 조회해주세요. `'failed'` 이면 그 이슈에는 리플레이가 없습니다.
61
+
62
+ ### 추가
63
+
64
+ - 공개 타입에 `HeadlessVideoUpload`·`HeadlessAttachmentUpload`, 스냅샷 필드 `videoUploads`·`attachmentUploads`, 이슈 필드 `video_status`·`replay_status`, 메서드 `retryVideoUpload(issueId)` 를 추가했습니다. `retryVideoUpload` 는 영상과 세션 리플레이·웹소켓 로그의 실패한 업로드를 함께 다시 올립니다.
65
+
66
+ ### 개선
67
+
68
+ - 영상 이슈를 제출하면 영상 업로드를 기다리지 않고 바로 이슈가 생성되고 입력창이 닫힙니다. 영상은 이어서 업로드되며 툴바에서 진행률을 확인합니다. 업로드가 끝나면 이슈에 첨부됩니다.
69
+ - 세션 리플레이와 웹소켓 로그도 업로드를 기다리지 않고 이슈를 먼저 생성합니다. 업로드가 끝나면 이슈에 첨부됩니다.
70
+ - 업로드 중에 페이지를 닫거나 이동해도 24시간 안에 같은 사이트를 다시 열면 이어서 업로드합니다. 업로드할 데이터는 그동안 고객 사이트의 IndexedDB 에 보관합니다.
71
+ - 같은 사이트를 여러 탭으로 열어도 업로드는 한 탭에서만 진행됩니다. 그 탭을 닫으면 사이트를 다시 열었을 때 이어서 업로드합니다.
72
+ - 영상과 세션 리플레이가 함께 있는 이슈는 업로드 결과를 알림 하나로 보여줍니다. 세션 리플레이만 있는 이슈는 업로드에 실패했을 때만 알립니다.
73
+ - 오프라인일 때 실패한 업로드는 실패로 알리지 않고 연결이 돌아오면 이어서 업로드합니다. 같은 이슈의 업로드가 이후 끝나면 앞서 띄운 실패 알림을 닫습니다.
74
+ - 화면 녹화 비트레이트를 1.5Mbps 로 낮췄습니다. 2분 녹화가 약 23MB 입니다.
75
+ - 이슈 입력창이 열려 있으면 녹화 단축키가 동작하지 않습니다.
76
+ - SDK 가 미디어를 업로드하는 요청은 이슈의 네트워크 로그에 기록하지 않습니다.
77
+ - 요청 한도(429)에 걸리면 서버가 알려준 시간만큼 기다렸다가 한 번만 다시 조회합니다. 다시 보내도 결과가 같은 오류(400·403·404 등)는 재시도하지 않고, 서버 오류는 재시도 시점을 조금씩 달리해 요청이 한꺼번에 몰리지 않게 합니다.
78
+ - 위젯의 이슈 팝오버에서 요소 상세 스크린샷을 전체 화면 스크린샷보다 먼저 보여줍니다.
79
+ - 「미표시 스티커」를 「표시하지 못한 스티커」로 바꿨습니다. 위치를 찾지 못해 화면에 표시하지 못한 스티커라는 뜻을 분명히 했습니다.
80
+ - 등록된 고정 문구가 없어도 「고정 문구 선택」이 열리고, 어드민에서 등록하는 방법을 안내합니다.
81
+ - AI 작성 입력창 안내 문구에 기능 설명과 예시를 넣었습니다. 직접 작성 폼의 AI 작성 버튼 툴팁에도 같은 설명을 추가했습니다.
82
+
83
+ ### 수정
84
+
85
+ - 이슈 생성 요청이 실패하면 자동으로 다시 보내지 않습니다. 응답만 늦게 도착했을 때 같은 이슈가 두 번 생성될 수 있던 문제를 막았습니다.
86
+ - 이슈와 함께 저장되는 요소 상세 스크린샷을 같은 순간의 화면에서 잘라냅니다. 투명한 링크가 덮인 카드, 가운데 정렬된 모달, 캐러셀, 어두운 배경 위의 글자가 빈 이미지나 어긋난 위치로 저장되던 문제를 고쳤습니다. 요소 상세 스크린샷에는 화면에 보이던 부분과 요소 둘레 8px 이 함께 들어가고, 화면 밖으로 나간 부분은 잘립니다.
87
+ - 이슈 생성 폼이 열려 있는 동안 위젯 툴바가 빈 칸으로 보이던 문제를 고쳤습니다. 이제 폼이 열려 있는 동안에는 툴바를 숨기고, 이슈를 생성하거나 취소하면 옮겨 둔 자리에 다시 표시합니다.
88
+ - 페이지의 팝업이나 드롭다운이 열린 상태에서 툴바의 「이슈 생성」 같은 위젯 버튼을 클릭하면 팝업이 닫히던 문제를 고쳤습니다.
89
+ - 이슈 상세 화면의 로그 패널 구분선을 드래그하다가 위젯 안에서 마우스를 놓아도 크기 조절이 끝나지 않던 문제를 고쳤습니다.
90
+ - 위젯에서 선택 목록이나 대화상자가 열려 있을 때 위젯 안 다른 곳이나 페이지를 클릭하면 닫힙니다.
91
+ - 페이지의 팝업이 열린 상태에서 위젯 입력창에 포커스가 잡히지 않던 문제를 고쳤습니다.
92
+ - 이슈 설명의 빈 파일 링크와 Notion 체크박스 표시를 고쳤습니다.
93
+
5
94
  ## 0.11.0 - 2026-10-02
6
95
 
7
96
  ### 추가
@@ -0,0 +1,8 @@
1
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
2
+ function getDefaultExportFromCjs(x) {
3
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
+ }
5
+ export {
6
+ commonjsGlobal as c,
7
+ getDefaultExportFromCjs as g
8
+ };