@tienne/gestalt 0.98.0 → 0.100.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.
Files changed (175) hide show
  1. package/CLAUDE.md +2 -1
  2. package/README.md +3 -2
  3. package/dist/package.json +2 -2
  4. package/dist/plugin/research-sources/amplitude/SOURCE.md +28 -0
  5. package/dist/plugin/research-sources/app-store-reviews/SOURCE.md +25 -0
  6. package/dist/plugin/research-sources/app-store-search/SOURCE.md +25 -0
  7. package/dist/plugin/research-sources/tech-blog-search/SOURCE.md +27 -0
  8. package/dist/plugin/research-sources/uibowl/SOURCE.md +26 -0
  9. package/dist/plugin/research-sources/web-search/SOURCE.md +24 -0
  10. package/dist/plugin/skills/_shared/proactive-routing.md +5 -0
  11. package/dist/plugin/skills/architecture/SKILL.md +1 -1
  12. package/dist/plugin/skills/market-scan/SKILL.md +61 -0
  13. package/dist/plugin/skills/research/SKILL.md +438 -0
  14. package/dist/plugin/skills/research/references/design.md +938 -0
  15. package/dist/plugin/skills/research/references/output-template.md +366 -0
  16. package/dist/plugin/skills/research/scripts/pii-vision.swift +327 -0
  17. package/dist/plugin/skills/research/scripts/slide-extract.mjs +223 -0
  18. package/dist/plugin/skills/reverse-plan/SKILL.md +52 -0
  19. package/dist/plugin/skills/screen-ref/SKILL.md +63 -0
  20. package/dist/plugin/skills/ux-research/SKILL.md +51 -0
  21. package/dist/src/architecture/validator.d.ts +17 -1
  22. package/dist/src/architecture/validator.d.ts.map +1 -1
  23. package/dist/src/architecture/validator.js +61 -45
  24. package/dist/src/architecture/validator.js.map +1 -1
  25. package/dist/src/core/config.d.ts +17 -0
  26. package/dist/src/core/config.d.ts.map +1 -1
  27. package/dist/src/core/config.js +4 -0
  28. package/dist/src/core/config.js.map +1 -1
  29. package/dist/src/core/source-location.d.ts +32 -0
  30. package/dist/src/core/source-location.d.ts.map +1 -0
  31. package/dist/src/core/source-location.js +87 -0
  32. package/dist/src/core/source-location.js.map +1 -0
  33. package/dist/src/execute/orchestrators/evolution.d.ts +3 -1
  34. package/dist/src/execute/orchestrators/evolution.d.ts.map +1 -1
  35. package/dist/src/execute/orchestrators/evolution.js +4 -2
  36. package/dist/src/execute/orchestrators/evolution.js.map +1 -1
  37. package/dist/src/execute/orchestrators/execution.d.ts +3 -1
  38. package/dist/src/execute/orchestrators/execution.d.ts.map +1 -1
  39. package/dist/src/execute/orchestrators/execution.js +4 -2
  40. package/dist/src/execute/orchestrators/execution.js.map +1 -1
  41. package/dist/src/execute/passthrough-engine.d.ts +2 -1
  42. package/dist/src/execute/passthrough-engine.d.ts.map +1 -1
  43. package/dist/src/execute/passthrough-engine.js +3 -3
  44. package/dist/src/execute/passthrough-engine.js.map +1 -1
  45. package/dist/src/execute/prompts.d.ts.map +1 -1
  46. package/dist/src/execute/prompts.js +20 -2
  47. package/dist/src/execute/prompts.js.map +1 -1
  48. package/dist/src/mcp/schemas.d.ts +93 -0
  49. package/dist/src/mcp/schemas.d.ts.map +1 -1
  50. package/dist/src/mcp/schemas.js +110 -0
  51. package/dist/src/mcp/schemas.js.map +1 -1
  52. package/dist/src/mcp/server.d.ts.map +1 -1
  53. package/dist/src/mcp/server.js +12 -2
  54. package/dist/src/mcp/server.js.map +1 -1
  55. package/dist/src/mcp/tools/execute/evaluate.js +1 -1
  56. package/dist/src/mcp/tools/execute/evaluate.js.map +1 -1
  57. package/dist/src/mcp/tools/research-passthrough.d.ts +21 -0
  58. package/dist/src/mcp/tools/research-passthrough.d.ts.map +1 -0
  59. package/dist/src/mcp/tools/research-passthrough.js +566 -0
  60. package/dist/src/mcp/tools/research-passthrough.js.map +1 -0
  61. package/dist/src/memory/project-memory-store.d.ts +7 -0
  62. package/dist/src/memory/project-memory-store.d.ts.map +1 -1
  63. package/dist/src/memory/project-memory-store.js +17 -0
  64. package/dist/src/memory/project-memory-store.js.map +1 -1
  65. package/dist/src/research/canvas-view.d.ts +5 -0
  66. package/dist/src/research/canvas-view.d.ts.map +1 -0
  67. package/dist/src/research/canvas-view.js +274 -0
  68. package/dist/src/research/canvas-view.js.map +1 -0
  69. package/dist/src/research/evidence.d.ts +145 -0
  70. package/dist/src/research/evidence.d.ts.map +1 -0
  71. package/dist/src/research/evidence.js +50 -0
  72. package/dist/src/research/evidence.js.map +1 -0
  73. package/dist/src/research/figma-plan.d.ts +80 -0
  74. package/dist/src/research/figma-plan.d.ts.map +1 -0
  75. package/dist/src/research/figma-plan.js +527 -0
  76. package/dist/src/research/figma-plan.js.map +1 -0
  77. package/dist/src/research/figma-script.d.ts +19 -0
  78. package/dist/src/research/figma-script.d.ts.map +1 -0
  79. package/dist/src/research/figma-script.js +363 -0
  80. package/dist/src/research/figma-script.js.map +1 -0
  81. package/dist/src/research/index.d.ts +8 -0
  82. package/dist/src/research/index.d.ts.map +1 -0
  83. package/dist/src/research/index.js +8 -0
  84. package/dist/src/research/index.js.map +1 -0
  85. package/dist/src/research/pii-core.d.ts +16 -0
  86. package/dist/src/research/pii-core.d.ts.map +1 -0
  87. package/dist/src/research/pii-core.js +345 -0
  88. package/dist/src/research/pii-core.js.map +1 -0
  89. package/dist/src/research/pii-dom.d.ts +13 -0
  90. package/dist/src/research/pii-dom.d.ts.map +1 -0
  91. package/dist/src/research/pii-dom.js +208 -0
  92. package/dist/src/research/pii-dom.js.map +1 -0
  93. package/dist/src/research/pii-image.d.ts +71 -0
  94. package/dist/src/research/pii-image.d.ts.map +1 -0
  95. package/dist/src/research/pii-image.js +163 -0
  96. package/dist/src/research/pii-image.js.map +1 -0
  97. package/dist/src/research/pii.d.ts +21 -0
  98. package/dist/src/research/pii.d.ts.map +1 -0
  99. package/dist/src/research/pii.js +47 -0
  100. package/dist/src/research/pii.js.map +1 -0
  101. package/dist/src/research/product-profile.d.ts +108 -0
  102. package/dist/src/research/product-profile.d.ts.map +1 -0
  103. package/dist/src/research/product-profile.js +104 -0
  104. package/dist/src/research/product-profile.js.map +1 -0
  105. package/dist/src/research/render-html.d.ts +203 -0
  106. package/dist/src/research/render-html.d.ts.map +1 -0
  107. package/dist/src/research/render-html.js +901 -0
  108. package/dist/src/research/render-html.js.map +1 -0
  109. package/dist/src/research/schema-base.d.ts +5 -0
  110. package/dist/src/research/schema-base.d.ts.map +1 -0
  111. package/dist/src/research/schema-base.js +10 -0
  112. package/dist/src/research/schema-base.js.map +1 -0
  113. package/dist/src/research/schema.d.ts +5142 -0
  114. package/dist/src/research/schema.d.ts.map +1 -0
  115. package/dist/src/research/schema.js +991 -0
  116. package/dist/src/research/schema.js.map +1 -0
  117. package/dist/src/research/source-create.d.ts +79 -0
  118. package/dist/src/research/source-create.d.ts.map +1 -0
  119. package/dist/src/research/source-create.js +226 -0
  120. package/dist/src/research/source-create.js.map +1 -0
  121. package/dist/src/research/source-registry.d.ts +29 -0
  122. package/dist/src/research/source-registry.d.ts.map +1 -0
  123. package/dist/src/research/source-registry.js +74 -0
  124. package/dist/src/research/source-registry.js.map +1 -0
  125. package/dist/src/research/source-schema.d.ts +158 -0
  126. package/dist/src/research/source-schema.d.ts.map +1 -0
  127. package/dist/src/research/source-schema.js +215 -0
  128. package/dist/src/research/source-schema.js.map +1 -0
  129. package/dist/src/research/source-status.d.ts +40 -0
  130. package/dist/src/research/source-status.d.ts.map +1 -0
  131. package/dist/src/research/source-status.js +109 -0
  132. package/dist/src/research/source-status.js.map +1 -0
  133. package/dist/src/research/store.d.ts +24 -0
  134. package/dist/src/research/store.d.ts.map +1 -0
  135. package/dist/src/research/store.js +60 -0
  136. package/dist/src/research/store.js.map +1 -0
  137. package/dist/src/research/target-view.d.ts +33 -0
  138. package/dist/src/research/target-view.d.ts.map +1 -0
  139. package/dist/src/research/target-view.js +133 -0
  140. package/dist/src/research/target-view.js.map +1 -0
  141. package/dist/src/research/target.d.ts +883 -0
  142. package/dist/src/research/target.d.ts.map +1 -0
  143. package/dist/src/research/target.js +323 -0
  144. package/dist/src/research/target.js.map +1 -0
  145. package/dist/src/research/video-transfer.d.ts +28 -0
  146. package/dist/src/research/video-transfer.d.ts.map +1 -0
  147. package/dist/src/research/video-transfer.js +100 -0
  148. package/dist/src/research/video-transfer.js.map +1 -0
  149. package/dist/src/spec/generator.d.ts.map +1 -1
  150. package/dist/src/spec/generator.js +3 -2
  151. package/dist/src/spec/generator.js.map +1 -1
  152. package/dist/src/spec/passthrough-generator.d.ts.map +1 -1
  153. package/dist/src/spec/passthrough-generator.js +6 -4
  154. package/dist/src/spec/passthrough-generator.js.map +1 -1
  155. package/package.json +2 -2
  156. package/plugin/.codex-plugin/plugin.json +1 -1
  157. package/plugin/.mcp.json +1 -1
  158. package/plugin/mcp.json +1 -1
  159. package/plugin/research-sources/amplitude/SOURCE.md +28 -0
  160. package/plugin/research-sources/app-store-reviews/SOURCE.md +25 -0
  161. package/plugin/research-sources/app-store-search/SOURCE.md +25 -0
  162. package/plugin/research-sources/tech-blog-search/SOURCE.md +27 -0
  163. package/plugin/research-sources/uibowl/SOURCE.md +26 -0
  164. package/plugin/research-sources/web-search/SOURCE.md +24 -0
  165. package/plugin/skills/_shared/proactive-routing.md +5 -0
  166. package/plugin/skills/architecture/SKILL.md +1 -1
  167. package/plugin/skills/market-scan/SKILL.md +61 -0
  168. package/plugin/skills/research/SKILL.md +438 -0
  169. package/plugin/skills/research/references/design.md +938 -0
  170. package/plugin/skills/research/references/output-template.md +366 -0
  171. package/plugin/skills/research/scripts/pii-vision.swift +327 -0
  172. package/plugin/skills/research/scripts/slide-extract.mjs +223 -0
  173. package/plugin/skills/reverse-plan/SKILL.md +52 -0
  174. package/plugin/skills/screen-ref/SKILL.md +63 -0
  175. package/plugin/skills/ux-research/SKILL.md +51 -0
@@ -0,0 +1,345 @@
1
+ /**
2
+ * 개인정보 탐지와 가짜 값 치환 코어.
3
+ *
4
+ * Node(이미지 경로의 OCR 결과 글자)와 브라우저(DOM 글자)가 같은 구현을 쓰도록 소스 문자열로
5
+ * 둔다. `Function.toString()`으로 뽑지 않는 건 번들러가 함수 안에 헬퍼를 끼워 넣어 브라우저에서
6
+ * 깨지기 때문이다. 이 문자열은 `node:vm`과 `page.evaluate` 양쪽에서 그대로 평가된다.
7
+ *
8
+ * 규칙
9
+ * - 실제 값과 가명의 대응표를 만들지 않는다. 가명은 `seed + 종류 + 정규화한 값`의 해시로
10
+ * 정해서, 같은 값이면 같은 가명이 나오지만 가명에서 실제 값을 되돌릴 수 없다.
11
+ * - 이 소스 안에서 백틱과 `${`를 쓰지 않는다. String.raw가 깨진다.
12
+ * - 못 잡는 것: 라벨 없는 이름, 성씨 목록 밖의 이름, 사진 속 글자가 아닌 정보. `pii: none`은
13
+ * "탐지기가 돌았고 0건"이라는 뜻이지 개인정보가 없다는 보증이 아니다.
14
+ */
15
+ export const PII_CORE_SOURCE = String.raw `(function () {
16
+ var SURNAMES = '김이박최정강조윤장임한오서신권황안송류전홍고문양손배백허유남심노하곽성차주우구민나진지엄채원천방공현함변염여추도소석선설마길연위표명기반왕금옥육인맹제모탁국어은편용';
17
+ var COMPOUND_SURNAMES = ['남궁', '선우', '독고', '황보', '제갈', '사공', '서문', '동방'];
18
+ var NOT_NAMES = ['고객', '선생', '손님', '구매', '이용', '기사', '주인', '입력', '필수', '선택', '확인', '정보', '변경', '등록', '수정', '삭제', '조회', '주문', '배송', '전체', '회원', '사용', '결제', '인증', '번호', '주소', '이름', '성명', '연락'];
19
+ var POOL = {
20
+ 2: ['이솔', '김하', '박온', '최윤', '정서', '강율', '조안', '한결'],
21
+ 3: ['홍길동', '김철수', '이영희', '박민수', '최지우', '정수민', '강다은', '조현우', '윤서연', '한지민'],
22
+ 4: ['남궁민수', '선우지안', '독고서진', '황보라희', '제갈민준', '사공유나', '서문하늘', '동방지후']
23
+ };
24
+ var LABELS = {
25
+ name: '이름|성명|성함|수령인|받는\\s?분|보내는\\s?분|예금주|구매자|주문자|수취인|대표자|대표이사|대표(?=\\s*[::])',
26
+ birth: '생년월일|생일',
27
+ address: '주소|배송지|배송\\s?주소|도로명',
28
+ account: '환불\\s?계좌|입금\\s?계좌|계좌\\s?번호|계좌',
29
+ order: '주문\\s?번호|예약\\s?번호|승인\\s?번호|운송장\\s?번호|거래\\s?번호',
30
+ biz: '사업자\\s?등록\\s?번호|사업자\\s?번호|법인\\s?등록\\s?번호|통신판매업\\s?신고(?:\\s?번호)?|통신판매업\\s?번호',
31
+ gift: '바코드(?:\\s?번호)?|PIN(?:\\s?번호)?|핀\\s?번호|쿠폰\\s?번호|교환\\s?번호|인증\\s?번호|시리얼(?:\\s?번호)?|상품권\\s?번호|기프티콘\\s?번호',
32
+ phone: '전화번호|휴대폰(?:\\s?번호)?|핸드폰(?:\\s?번호)?|연락처|전화',
33
+ email: '이메일|메일'
34
+ };
35
+ var LABEL_ONLY = {};
36
+ var LABEL_INLINE = {};
37
+ Object.keys(LABELS).forEach(function (kind) {
38
+ LABEL_ONLY[kind] = new RegExp('^(?:' + LABELS[kind] + ')\\s*[::]?$');
39
+ });
40
+ var VALUE_PATTERNS = {
41
+ name: '[가-힣]{2,4}',
42
+ birth: '\\d{4}[.\\-/년 ]+\\d{1,2}[.\\-/월 ]+\\d{1,2}일?|\\d{8}|\\d{6}',
43
+ address: '[^\\n]{4,100}',
44
+ account: '\\d[\\d-]{7,24}\\d',
45
+ order: '[A-Za-z0-9-]{6,32}',
46
+ biz: '[0-9][0-9A-Za-z가-힣-]{5,28}',
47
+ gift: '[A-Za-z0-9][A-Za-z0-9 -]{4,30}[A-Za-z0-9]',
48
+ phone: '\\+?[\\d][\\d .-]{7,16}\\d',
49
+ email: '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}'
50
+ };
51
+ Object.keys(LABELS).forEach(function (kind) {
52
+ LABEL_INLINE[kind] = new RegExp('(?:' + LABELS[kind] + ')(?:\\s*[::]\\s*|\\s+)(' + VALUE_PATTERNS[kind] + ')(님)?', 'dg');
53
+ });
54
+
55
+ var NIM_NAME = /(?<![가-힣])([가-힣]{2,4})님/dg;
56
+ var MASKED_NIM_NAME = /(?<![가-힣])([가-힣]{1,3}[**○●]{1,2}[가-힣]{0,2})님/dg;
57
+ var EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
58
+ var PHONE = /(?<!\d)(?:\+82[-. ]?)?0\d{1,2}[-. ]?\d{3,4}[-. ]?\d{4}(?!\d)/g;
59
+ var RRN = /(?<!\d)\d{6}[- ]?[1-8]\d{6}(?!\d)/g;
60
+ var CARD = /(?<!\d)(?:\d{4}[- ]){3}\d{4}(?!\d)|(?<!\d)\d{16}(?!\d)/g;
61
+ var LONG_CODE = /(?<!\d)\d{4}(?:[- ]?\d{4}){2,}(?!\d)/g;
62
+ var ROAD_ADDRESS = /[가-힣]{2,6}(?:특별시|광역시|특별자치시|특별자치도|도|시)\s[가-힣]{1,6}(?:시|군|구)\s[가-힣0-9]{1,12}(?:로|길)\s?\d{1,4}(?:-\d{1,4})?(?:\s?[0-9가-힣-]{1,12}(?:동|호|층))*/g;
63
+
64
+ function hashString(str, seedNum) {
65
+ var h1 = 0xdeadbeef ^ seedNum;
66
+ var h2 = 0x41c6ce57 ^ seedNum;
67
+ for (var i = 0; i < str.length; i++) {
68
+ var ch = str.charCodeAt(i);
69
+ h1 = Math.imul(h1 ^ ch, 2654435761);
70
+ h2 = Math.imul(h2 ^ ch, 1597334677);
71
+ }
72
+ h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
73
+ h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
74
+ return 4294967296 * (2097151 & h2) + (h1 >>> 0);
75
+ }
76
+
77
+ function pad(n, width) {
78
+ var s = String(n);
79
+ while (s.length < width) s = '0' + s;
80
+ return s;
81
+ }
82
+
83
+ function startsWithSurname(word) {
84
+ if (word.length >= 4 && COMPOUND_SURNAMES.indexOf(word.slice(0, 2)) >= 0) return true;
85
+ return SURNAMES.indexOf(word.charAt(0)) >= 0;
86
+ }
87
+
88
+ function plausibleName(word) {
89
+ if (!/^[가-힣]{2,4}$/.test(word)) return false;
90
+ if (NOT_NAMES.indexOf(word.slice(0, 2)) >= 0) return false;
91
+ return startsWithSurname(word);
92
+ }
93
+
94
+ function plausibleMaskedName(word) {
95
+ if (word.length > 4) return false;
96
+ if (NOT_NAMES.indexOf(word.slice(0, 2)) >= 0) return false;
97
+ return startsWithSurname(word);
98
+ }
99
+
100
+ function createPii(seed) {
101
+ var seedNum = hashString(String(seed), 7) % 2147483647;
102
+
103
+ function keyed(kind, value) {
104
+ return hashString(kind + '\u0000' + value, seedNum);
105
+ }
106
+ function tail4(kind, value) {
107
+ return pad(keyed(kind, value) % 10000, 4);
108
+ }
109
+ function digitsOf(text) {
110
+ return text.replace(/\D/g, '');
111
+ }
112
+
113
+ function fakePhone(value) {
114
+ var key = digitsOf(value);
115
+ var groups = value.split(/(\d+)/);
116
+ var numericIdx = [];
117
+ for (var i = 0; i < groups.length; i++) if (/^\d+$/.test(groups[i])) numericIdx.push(i);
118
+ var tail = tail4('phone', key);
119
+ if (numericIdx.length === 1) {
120
+ var only = groups[numericIdx[0]];
121
+ var head = only.length <= 10 && only.indexOf('02') === 0 ? 2 : 3;
122
+ groups[numericIdx[0]] = only.slice(0, head) + new Array(only.length - head - 3).join('0') + tail;
123
+ return groups.join('');
124
+ }
125
+ var keep = value.indexOf('+82') === 0 ? 2 : 1;
126
+ for (var j = keep; j < numericIdx.length; j++) {
127
+ var idx = numericIdx[j];
128
+ groups[idx] = j === numericIdx.length - 1 ? tail : new Array(groups[idx].length + 1).join('0');
129
+ }
130
+ return groups.join('');
131
+ }
132
+
133
+ function fakeEmail(value) {
134
+ var h = keyed('email', value.toLowerCase());
135
+ return 'user' + (100 + (h % 900)) + '@example.com';
136
+ }
137
+
138
+ function fakeName(word, suffix) {
139
+ var len = word.length;
140
+ var list = POOL[len] || POOL[3];
141
+ return list[keyed('name', word) % list.length] + (suffix || '');
142
+ }
143
+
144
+ function fakeDateParts(value) {
145
+ var h = keyed('date', digitsOf(value));
146
+ return { y: 1975 + (h % 30), m: 1 + (Math.floor(h / 30) % 12), d: 1 + (Math.floor(h / 360) % 28) };
147
+ }
148
+
149
+ function fakeBirth(value) {
150
+ var p = fakeDateParts(value);
151
+ var m = /^(\d{4})([.\-/년 ]+)(\d{1,2})([.\-/월 ]+)(\d{1,2})(일?)$/.exec(value);
152
+ if (m) {
153
+ var mm = m[3].length === 2 ? pad(p.m, 2) : String(p.m);
154
+ var dd = m[5].length === 2 ? pad(p.d, 2) : String(p.d);
155
+ return p.y + m[2] + mm + m[4] + dd + m[6];
156
+ }
157
+ if (/^\d{8}$/.test(value)) return p.y + pad(p.m, 2) + pad(p.d, 2);
158
+ if (/^\d{6}$/.test(value)) return pad(p.y % 100, 2) + pad(p.m, 2) + pad(p.d, 2);
159
+ return value.replace(/\d/g, '0');
160
+ }
161
+
162
+ function fakeRrn(value) {
163
+ var p = fakeDateParts(value);
164
+ var sep = /[- ]/.exec(value);
165
+ return pad(p.y % 100, 2) + pad(p.m, 2) + pad(p.d, 2) + (sep ? sep[0] : '') + '1000000';
166
+ }
167
+
168
+ function maskDigits(kind, value, keepLetters) {
169
+ var key = kind + ':' + value.replace(/[^A-Za-z0-9]/g, '');
170
+ var tail = tail4(kind, key);
171
+ var total = 0;
172
+ for (var i = 0; i < value.length; i++) if (/\d/.test(value.charAt(i))) total++;
173
+ var seen = 0;
174
+ var out = '';
175
+ for (var k = 0; k < value.length; k++) {
176
+ var c = value.charAt(k);
177
+ if (/\d/.test(c)) {
178
+ seen++;
179
+ out += total >= 4 && seen > total - 4 ? tail.charAt(seen - (total - 4) - 1) : '0';
180
+ } else if (/[A-Za-z]/.test(c)) {
181
+ out += keepLetters ? c : 'X';
182
+ } else {
183
+ out += c;
184
+ }
185
+ }
186
+ return out;
187
+ }
188
+
189
+ function fakeCard(value) {
190
+ return maskDigits('card', value, true);
191
+ }
192
+
193
+ function fakeAddress(value) {
194
+ var h = keyed('address', value.replace(/\s+/g, ''));
195
+ return '서울특별시 샘플구 예시로 ' + (10 + (h % 90));
196
+ }
197
+
198
+ function fakeDigits(value) {
199
+ return maskDigits('barcode', value, false);
200
+ }
201
+
202
+ function validAddressValue(value) {
203
+ return /[가-힣]/.test(value) && /\d/.test(value);
204
+ }
205
+
206
+ var REPLACERS = {
207
+ email: function (v) { return fakeEmail(v); },
208
+ phone: function (v) { return fakePhone(v); },
209
+ card: function (v) { return fakeCard(v); },
210
+ birth: function (v) { return fakeBirth(v); },
211
+ address: function (v) { return fakeAddress(v); },
212
+ account: function (v) { return maskDigits('account', v, true); },
213
+ order: function (v) { return maskDigits('order', v, true); },
214
+ biz: function (v) { return maskDigits('biz', v, true); },
215
+ gift: function (v) { return maskDigits('gift', v, false); }
216
+ };
217
+
218
+ /** 글 한 덩어리에서 개인정보 구간을 찾는다. ctxKind가 있으면 글 전체를 그 종류의 값으로 본다 */
219
+ function detect(text, ctxKind) {
220
+ var found = [];
221
+ function add(kind, start, end, replacement) {
222
+ if (replacement !== text.slice(start, end)) found.push({ kind: kind, start: start, end: end, replacement: replacement });
223
+ }
224
+
225
+ if (ctxKind) {
226
+ var lead = text.length - text.replace(/^\s+/, '').length;
227
+ var body = text.trim();
228
+ if (body) {
229
+ if (ctxKind === 'name') {
230
+ var suffix = /님$/.test(body) ? '님' : '';
231
+ var word = suffix ? body.slice(0, -1) : body;
232
+ if (plausibleName(word)) add('name', lead, lead + body.length, fakeName(word, suffix));
233
+ } else if (ctxKind === 'address') {
234
+ if (validAddressValue(body)) add('address', lead, lead + body.length, fakeAddress(body));
235
+ } else if (REPLACERS[ctxKind] && /\d|@/.test(body)) {
236
+ add(ctxKind, lead, lead + body.length, REPLACERS[ctxKind](body));
237
+ }
238
+ }
239
+ }
240
+
241
+ var m;
242
+ Object.keys(LABEL_INLINE).forEach(function (kind) {
243
+ var re = new RegExp(LABEL_INLINE[kind].source, 'dg');
244
+ while ((m = re.exec(text)) !== null) {
245
+ var value = m[1];
246
+ var span = m.indices[1];
247
+ if (kind === 'name') {
248
+ var nameSuffix = m[2] || '';
249
+ var nameWord = value;
250
+ if (!nameSuffix && value.length >= 3 && /님$/.test(value)) {
251
+ nameSuffix = '님';
252
+ nameWord = value.slice(0, -1);
253
+ }
254
+ if (plausibleName(nameWord)) add('name', span[0], span[1] + (m[2] ? 1 : 0), fakeName(nameWord, nameSuffix));
255
+ } else if (kind === 'address') {
256
+ if (validAddressValue(value)) add('address', span[0], span[1], fakeAddress(value));
257
+ } else if (kind === 'birth' || kind === 'phone' || kind === 'account' || kind === 'order' || kind === 'biz' || kind === 'gift' || kind === 'email') {
258
+ if (/\d|@/.test(value)) add(kind, span[0], span[1], REPLACERS[kind](value));
259
+ }
260
+ if (m[0].length === 0) re.lastIndex++;
261
+ }
262
+ });
263
+
264
+ var re2 = new RegExp(NIM_NAME.source, 'dg');
265
+ while ((m = re2.exec(text)) !== null) {
266
+ if (plausibleName(m[1])) add('name', m.indices[1][0], m.indices[0][1], fakeName(m[1], '님'));
267
+ }
268
+ var re3 = new RegExp(MASKED_NIM_NAME.source, 'dg');
269
+ while ((m = re3.exec(text)) !== null) {
270
+ if (plausibleMaskedName(m[1])) add('name', m.indices[1][0], m.indices[0][1], fakeName(m[1], '님'));
271
+ }
272
+ EMAIL.lastIndex = 0;
273
+ while ((m = EMAIL.exec(text)) !== null) {
274
+ if (!/@example\.com$/i.test(m[0])) add('email', m.index, m.index + m[0].length, fakeEmail(m[0]));
275
+ }
276
+ [[PHONE, 'phone', fakePhone], [RRN, 'rrn', fakeRrn], [CARD, 'card', fakeCard], [ROAD_ADDRESS, 'address', fakeAddress], [LONG_CODE, 'gift', function (v) { return maskDigits('gift', v, false); }]].forEach(function (entry) {
277
+ var re3 = new RegExp(entry[0].source, 'g');
278
+ while ((m = re3.exec(text)) !== null) {
279
+ add(entry[1], m.index, m.index + m[0].length, entry[2](m[0]));
280
+ }
281
+ });
282
+
283
+ found.sort(function (a, b) { return a.start - b.start || (b.end - b.start) - (a.end - a.start); });
284
+ var kept = [];
285
+ var lastEnd = -1;
286
+ found.forEach(function (f) {
287
+ if (f.start >= lastEnd) {
288
+ kept.push(f);
289
+ lastEnd = f.end;
290
+ }
291
+ });
292
+ return kept;
293
+ }
294
+
295
+ function apply(text, spans) {
296
+ var out = '';
297
+ var pos = 0;
298
+ spans.forEach(function (s) {
299
+ out += text.slice(pos, s.start) + s.replacement;
300
+ pos = s.end;
301
+ });
302
+ return out + text.slice(pos);
303
+ }
304
+
305
+ function redactText(text, ctxKind) {
306
+ var spans = detect(text, ctxKind);
307
+ return { text: spans.length ? apply(text, spans) : text, spans: spans };
308
+ }
309
+
310
+ function labelKindOf(text) {
311
+ var t = text.trim();
312
+ if (t.length === 0 || t.length > 14) return null;
313
+ var kinds = Object.keys(LABEL_ONLY);
314
+ for (var i = 0; i < kinds.length; i++) if (LABEL_ONLY[kinds[i]].test(t)) return kinds[i];
315
+ return null;
316
+ }
317
+
318
+ function kindFromHints(hints) {
319
+ var h = String(hints).toLowerCase();
320
+ if (/email|e-mail|이메일/.test(h)) return 'email';
321
+ if (/tel|phone|mobile|휴대폰|전화|연락처/.test(h)) return 'phone';
322
+ if (/bday|birth|생년|생일/.test(h)) return 'birth';
323
+ if (/street|address|addr|주소|배송지/.test(h)) return 'address';
324
+ if (/cc-number|card|카드/.test(h)) return 'card';
325
+ if (/account|계좌/.test(h)) return 'account';
326
+ if (/order|주문|예약/.test(h)) return 'order';
327
+ if (/business|사업자|법인|통신판매/.test(h)) return 'biz';
328
+ if (/pin|barcode|coupon|gift|바코드|쿠폰|핀|교환|인증번호/.test(h)) return 'gift';
329
+ if (/name|이름|성명|수령|받는|예금주|대표자|대표이사/.test(h)) return 'name';
330
+ return null;
331
+ }
332
+
333
+ return {
334
+ detect: detect,
335
+ redactText: redactText,
336
+ labelKindOf: labelKindOf,
337
+ kindFromHints: kindFromHints,
338
+ fakeDigits: fakeDigits,
339
+ hash: function (kind, value) { return keyed(kind, value); }
340
+ };
341
+ }
342
+
343
+ return createPii;
344
+ })()`;
345
+ //# sourceMappingURL=pii-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii-core.js","sourceRoot":"","sources":["../../../src/research/pii-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyUpC,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface DomRedactionOptions {
2
+ /** true면 이후 화면이 바뀔 때마다(무한 스크롤, 지연 로딩) 다시 치환한다 */
3
+ observe?: boolean;
4
+ }
5
+ /**
6
+ * 웹 화면을 캡처하기 전에 DOM의 개인정보를 가짜 값으로 바꾸는 스크립트를 만든다.
7
+ * 세션이 aside나 chrome-devtools의 evaluate로 실행한다. 반환값은 바꾼 개수뿐이고 값은 담지 않는다.
8
+ *
9
+ * 못 건드리는 곳: 닫힌 shadow root, 다른 출처의 iframe, canvas에 그려진 글자.
10
+ * 이런 영역이 화면에 있으면 `pii: none`으로 적지 말고 `unchecked`로 남긴다.
11
+ */
12
+ export declare function buildDomRedactionScript(seed: string, options?: DomRedactionOptions): string;
13
+ //# sourceMappingURL=pii-dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii-dom.d.ts","sourceRoot":"","sources":["../../../src/research/pii-dom.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAgB/F"}
@@ -0,0 +1,208 @@
1
+ import { PII_CORE_SOURCE } from './pii-core.js';
2
+ /**
3
+ * 웹 화면을 캡처하기 전에 DOM의 개인정보를 가짜 값으로 바꾸는 스크립트를 만든다.
4
+ * 세션이 aside나 chrome-devtools의 evaluate로 실행한다. 반환값은 바꾼 개수뿐이고 값은 담지 않는다.
5
+ *
6
+ * 못 건드리는 곳: 닫힌 shadow root, 다른 출처의 iframe, canvas에 그려진 글자.
7
+ * 이런 영역이 화면에 있으면 `pii: none`으로 적지 말고 `unchecked`로 남긴다.
8
+ */
9
+ export function buildDomRedactionScript(seed, options = {}) {
10
+ const observe = options.observe === true;
11
+ return ('(function () {\n' +
12
+ 'var createPii = ' +
13
+ PII_CORE_SOURCE +
14
+ ';\n' +
15
+ 'var pii = createPii(' +
16
+ JSON.stringify(seed) +
17
+ ');\n' +
18
+ 'var OBSERVE = ' +
19
+ (observe ? 'true' : 'false') +
20
+ ';\n' +
21
+ DOM_BODY +
22
+ '\n})()');
23
+ }
24
+ const DOM_BODY = String.raw `
25
+ var AVATAR_RE = /avatar|profile|프로필|user-?photo|thumb-?user/i;
26
+ var BARCODE_RE = /barcode|qr-?code|qrcode|바코드|큐알/i;
27
+ var SKIP_TAGS = { SCRIPT: 1, STYLE: 1, NOSCRIPT: 1, TEXTAREA: 1 };
28
+ var AVATAR_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96"><rect width="96" height="96" fill="#e5e7eb"/><circle cx="48" cy="38" r="16" fill="#9ca3af"/><path d="M16 88c0-18 14-30 32-30s32 12 32 30z" fill="#9ca3af"/></svg>';
29
+ var AVATAR_URI = 'data:image/svg+xml;utf8,' + encodeURIComponent(AVATAR_SVG);
30
+
31
+ function barcodeUri(width, height, key) {
32
+ var bars = '';
33
+ var x = 0;
34
+ var i = 0;
35
+ while (x < width) {
36
+ var h = pii.hash('bar', key + ':' + i);
37
+ var w = 1 + (h % 3);
38
+ if (i % 2 === 0) bars += '<rect x="' + x + '" y="0" width="' + w + '" height="' + height + '" fill="#111827"/>';
39
+ x += w;
40
+ i++;
41
+ }
42
+ var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '" viewBox="0 0 ' + width + ' ' + height + '"><rect width="' + width + '" height="' + height + '" fill="#fff"/>' + bars + '</svg>';
43
+ return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg);
44
+ }
45
+
46
+ var counts = { text: 0, inputs: 0, attrs: 0, avatars: 0, barcodes: 0 };
47
+
48
+ function hintsOf(el) {
49
+ return [el.getAttribute('type'), el.getAttribute('name'), el.id, el.getAttribute('autocomplete'), el.getAttribute('placeholder'), el.getAttribute('aria-label'), el.getAttribute('inputmode')].join(' ');
50
+ }
51
+
52
+ function redactTextNodes(root) {
53
+ var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
54
+ acceptNode: function (node) {
55
+ var p = node.parentElement;
56
+ if (p && SKIP_TAGS[p.tagName]) return NodeFilter.FILTER_REJECT;
57
+ return NodeFilter.FILTER_ACCEPT;
58
+ }
59
+ });
60
+ var pending = null;
61
+ var node;
62
+ while ((node = walker.nextNode())) {
63
+ var text = node.nodeValue || '';
64
+ if (!text.trim()) continue;
65
+ var label = pii.labelKindOf(text);
66
+ if (label) {
67
+ pending = label;
68
+ continue;
69
+ }
70
+ var r = pii.redactText(text, pending);
71
+ pending = null;
72
+ if (r.spans.length) {
73
+ node.nodeValue = r.text;
74
+ counts.text += r.spans.length;
75
+ }
76
+ }
77
+ }
78
+
79
+ function redactInputs(root) {
80
+ var fields = root.querySelectorAll('input, textarea');
81
+ for (var i = 0; i < fields.length; i++) {
82
+ var el = fields[i];
83
+ var type = (el.getAttribute('type') || 'text').toLowerCase();
84
+ if (type === 'password' || type === 'hidden' || type === 'checkbox' || type === 'radio' || type === 'button' || type === 'submit') continue;
85
+ var value = el.value || '';
86
+ if (!value) continue;
87
+ var kind = pii.kindFromHints(hintsOf(el));
88
+ var r = pii.redactText(value, kind);
89
+ if (r.spans.length) {
90
+ el.value = r.text;
91
+ el.setAttribute('value', r.text);
92
+ counts.inputs += r.spans.length;
93
+ }
94
+ }
95
+ }
96
+
97
+ function redactAttributes(root) {
98
+ var names = ['alt', 'title', 'placeholder', 'aria-label'];
99
+ var els = root.querySelectorAll('[alt], [title], [placeholder], [aria-label]');
100
+ for (var i = 0; i < els.length; i++) {
101
+ for (var j = 0; j < names.length; j++) {
102
+ var v = els[i].getAttribute(names[j]);
103
+ if (!v) continue;
104
+ var r = pii.redactText(v, null);
105
+ if (r.spans.length) {
106
+ els[i].setAttribute(names[j], r.text);
107
+ counts.attrs += r.spans.length;
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ function classText(el) {
114
+ var c = el.getAttribute('class') || '';
115
+ return c + ' ' + (el.id || '') + ' ' + (el.getAttribute('alt') || '');
116
+ }
117
+
118
+ function redactAvatars(root) {
119
+ var imgs = root.querySelectorAll('img');
120
+ for (var i = 0; i < imgs.length; i++) {
121
+ var img = imgs[i];
122
+ if (img.getAttribute('data-pii-done')) continue;
123
+ if (AVATAR_RE.test(classText(img)) || AVATAR_RE.test(img.getAttribute('src') || '')) {
124
+ img.removeAttribute('srcset');
125
+ img.setAttribute('src', AVATAR_URI);
126
+ if (img.hasAttribute('alt')) img.setAttribute('alt', '프로필 사진');
127
+ img.removeAttribute('title');
128
+ img.setAttribute('data-pii-done', '1');
129
+ counts.avatars++;
130
+ }
131
+ }
132
+ var all = root.querySelectorAll('[class*="avatar" i], [class*="profile" i], [class*="프로필"]');
133
+ for (var k = 0; k < all.length; k++) {
134
+ var el = all[k];
135
+ if (el.tagName === 'IMG' || el.getAttribute('data-pii-done')) continue;
136
+ var bg = getComputedStyle(el).backgroundImage;
137
+ if (bg && bg !== 'none') {
138
+ el.style.backgroundImage = 'url("' + AVATAR_URI + '")';
139
+ el.setAttribute('data-pii-done', '1');
140
+ counts.avatars++;
141
+ }
142
+ }
143
+ }
144
+
145
+ function redactBarcodes(root) {
146
+ var els = root.querySelectorAll('img, canvas, svg, div, span');
147
+ for (var i = 0; i < els.length; i++) {
148
+ var el = els[i];
149
+ if (el.getAttribute('data-pii-done')) continue;
150
+ if (!BARCODE_RE.test(classText(el)) && !(el.tagName === 'IMG' && BARCODE_RE.test(el.getAttribute('src') || ''))) continue;
151
+ if (el.tagName !== 'IMG' && el.querySelector && el.querySelector('img, canvas, svg')) continue;
152
+ var rect = el.getBoundingClientRect();
153
+ var w = Math.max(60, Math.round(rect.width));
154
+ var h = Math.max(24, Math.round(rect.height));
155
+ var uri = barcodeUri(w, h, w + 'x' + h);
156
+ if (el.tagName === 'IMG') {
157
+ el.removeAttribute('srcset');
158
+ el.setAttribute('src', uri);
159
+ el.setAttribute('data-pii-done', '1');
160
+ } else if (el.tagName === 'DIV' || el.tagName === 'SPAN') {
161
+ el.style.backgroundImage = 'url("' + uri + '")';
162
+ el.style.backgroundSize = '100% 100%';
163
+ el.setAttribute('data-pii-done', '1');
164
+ } else {
165
+ var repl = document.createElement('img');
166
+ repl.setAttribute('src', uri);
167
+ repl.setAttribute('data-pii-done', '1');
168
+ repl.style.width = w + 'px';
169
+ repl.style.height = h + 'px';
170
+ el.replaceWith(repl);
171
+ }
172
+ counts.barcodes++;
173
+ }
174
+ }
175
+
176
+ function runAll() {
177
+ redactTextNodes(document.body);
178
+ redactInputs(document);
179
+ redactAttributes(document);
180
+ redactAvatars(document);
181
+ redactBarcodes(document);
182
+ }
183
+
184
+ function start() {
185
+ runAll();
186
+ if (OBSERVE && typeof MutationObserver !== 'undefined' && !window.__piiObserver) {
187
+ var timer = null;
188
+ window.__piiObserver = new MutationObserver(function () {
189
+ if (timer) return;
190
+ timer = setTimeout(function () {
191
+ timer = null;
192
+ window.__piiObserver.disconnect();
193
+ try { runAll(); } finally {
194
+ window.__piiObserver.observe(document.body, { childList: true, subtree: true, characterData: true });
195
+ }
196
+ }, 150);
197
+ });
198
+ window.__piiObserver.observe(document.body, { childList: true, subtree: true, characterData: true });
199
+ }
200
+ }
201
+
202
+ // addInitScript로 심으면 body가 생기기 전에 실행된다. 그때는 DOM이 준비되길 기다린다
203
+ if (document.body) start();
204
+ else document.addEventListener('DOMContentLoaded', start);
205
+
206
+ return counts;
207
+ `;
208
+ //# sourceMappingURL=pii-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii-dom.js","sourceRoot":"","sources":["../../../src/research/pii-dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOhD;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,UAA+B,EAAE;IACrF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC;IACzC,OAAO,CACL,kBAAkB;QAClB,kBAAkB;QAClB,eAAe;QACf,KAAK;QACL,sBAAsB;QACtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QACpB,MAAM;QACN,gBAAgB;QAChB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC5B,KAAK;QACL,QAAQ;QACR,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuL1B,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { PiiRedactor } from './pii.js';
2
+ export interface VisionBox {
3
+ x: number;
4
+ y: number;
5
+ w: number;
6
+ h: number;
7
+ }
8
+ export interface OcrToken {
9
+ start: number;
10
+ end: number;
11
+ box: VisionBox;
12
+ }
13
+ export interface OcrLine {
14
+ text: string;
15
+ box: VisionBox;
16
+ confidence: number;
17
+ tokens: OcrToken[];
18
+ }
19
+ export interface OcrResult {
20
+ width: number;
21
+ height: number;
22
+ languages: string[];
23
+ lines: OcrLine[];
24
+ faces: VisionBox[];
25
+ barcodes: {
26
+ payload?: string | null;
27
+ symbology: string;
28
+ box: VisionBox;
29
+ }[];
30
+ }
31
+ export interface PaintItem {
32
+ type: 'text' | 'avatar' | 'barcode';
33
+ box: VisionBox;
34
+ text?: string;
35
+ }
36
+ export interface RedactionPlan {
37
+ items: PaintItem[];
38
+ counts: {
39
+ text: number;
40
+ avatars: number;
41
+ barcodes: number;
42
+ };
43
+ }
44
+ export type PiiState = 'replaced' | 'none' | 'unchecked';
45
+ export interface ImageRedactionResult {
46
+ pii: PiiState;
47
+ outputPath: string;
48
+ counts: RedactionPlan['counts'];
49
+ warnings: string[];
50
+ }
51
+ /** OCR 결과에서 가려야 할 칸과 그 자리에 그릴 가짜 값을 정한다. 이미지는 건드리지 않는다 */
52
+ export declare function planRedaction(ocr: OcrResult, pii: PiiRedactor): RedactionPlan;
53
+ export type VisionRunner = (args: string[]) => Promise<string>;
54
+ export declare function swiftRunner(scriptPath: string, timeoutMs?: number): VisionRunner;
55
+ /** macOS이고 swift 도구체인이 있을 때만 Vision을 쓸 수 있다. 첫 호출 결과를 프로세스 동안 재사용한다 */
56
+ export declare function isVisionAvailable(): Promise<boolean>;
57
+ export declare function outputExtFor(inputPath: string, replaced: boolean): string;
58
+ export interface RedactImageOptions {
59
+ inputPath: string;
60
+ /** 확장자를 뺀 출력 경로. 실제 확장자는 결과의 outputPath에 있다 */
61
+ outputBase: string;
62
+ pii: PiiRedactor;
63
+ run: VisionRunner | undefined;
64
+ }
65
+ /**
66
+ * 이미지 한 장의 개인정보를 가짜 값으로 바꿔 저장한다.
67
+ * - Vision을 못 쓰면 원본을 그대로 복사하고 `unchecked`로 남긴다
68
+ * - 탐지가 0건이면 원본을 복사하고 `none`이다. 라벨 없는 이름은 못 잡을 수 있어서 보증은 아니다
69
+ */
70
+ export declare function redactImageFile(opts: RedactImageOptions): Promise<ImageRedactionResult>;
71
+ //# sourceMappingURL=pii-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii-image.d.ts","sourceRoot":"","sources":["../../../src/research/pii-image.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI5C,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,SAAS,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;CAC5E;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACpC,GAAG,EAAE,SAAS,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,QAAQ,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA2DD,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,aAAa,CAoC7E;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE/D,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,SAAU,GAAG,YAAY,CAQjF;AAID,uEAAuE;AACvE,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CASpD;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAIzE;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,YAAY,GAAG,SAAS,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0C7F"}