@mandujs/core 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +4 -4
- package/README.md +653 -653
- package/package.json +1 -1
- package/src/bundler/build.ts +91 -91
- package/src/bundler/css.ts +302 -302
- package/src/client/Link.tsx +227 -227
- package/src/client/globals.ts +44 -44
- package/src/client/hooks.ts +267 -267
- package/src/client/index.ts +5 -5
- package/src/client/island.ts +8 -8
- package/src/client/router.ts +435 -435
- package/src/client/runtime.ts +23 -23
- package/src/client/serialize.ts +404 -404
- package/src/client/window-state.ts +101 -101
- package/src/config/mandu.ts +9 -0
- package/src/config/validate.ts +12 -0
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/content-layer.ts +314 -314
- package/src/content/content.test.ts +433 -433
- package/src/content/data-store.ts +245 -245
- package/src/content/digest.ts +133 -133
- package/src/content/index.ts +164 -164
- package/src/content/loader-context.ts +172 -172
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +169 -169
- package/src/content/loaders/glob.ts +252 -252
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/client.ts +16 -16
- package/src/contract/define.ts +459 -459
- package/src/contract/handler.ts +10 -10
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +404 -404
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/registry.ts +568 -568
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/contract/validator.ts +32 -32
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +465 -465
- package/src/devtools/client/catchers/error-catcher.ts +327 -327
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/catchers/network-proxy.ts +363 -363
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/kitchen-root.tsx +362 -362
- package/src/devtools/client/components/mandu-character.tsx +241 -241
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
- package/src/devtools/client/components/panel/index.ts +32 -32
- package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
- package/src/devtools/client/components/panel/network-panel.tsx +292 -292
- package/src/devtools/client/components/panel/panel-container.tsx +259 -259
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/client/state-manager.ts +478 -478
- package/src/devtools/design-tokens.ts +263 -263
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +266 -266
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +444 -444
- package/src/devtools/types.ts +319 -319
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +222 -222
- package/src/devtools/worker/worker-manager.ts +409 -409
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +46 -46
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/auth.ts +308 -308
- package/src/filling/context.ts +24 -1
- package/src/filling/deps.ts +238 -238
- package/src/filling/index.ts +2 -0
- package/src/filling/sse.test.ts +168 -0
- package/src/filling/sse.ts +162 -0
- package/src/generator/index.ts +3 -3
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/ast-analyzer.ts +806 -806
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/presets/index.ts +291 -291
- package/src/guard/reporter.ts +445 -445
- package/src/guard/rules.ts +12 -12
- package/src/guard/statistics.ts +578 -578
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/types.ts +348 -348
- package/src/guard/validator.ts +834 -834
- package/src/guard/watcher.ts +404 -404
- package/src/index.ts +6 -1
- package/src/intent/index.ts +310 -310
- package/src/island/index.ts +304 -304
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/plugins/index.ts +38 -38
- package/src/plugins/registry.ts +377 -377
- package/src/plugins/types.ts +363 -363
- package/src/report/index.ts +1 -1
- package/src/router/fs-patterns.ts +387 -387
- package/src/router/fs-scanner.ts +497 -497
- package/src/runtime/boundary.tsx +232 -232
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/escape.ts +44 -0
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/logger.ts +677 -677
- package/src/runtime/router.test.ts +476 -476
- package/src/runtime/router.ts +105 -105
- package/src/runtime/security.ts +155 -155
- package/src/runtime/server.ts +257 -0
- package/src/runtime/session-key.ts +328 -328
- package/src/runtime/ssr.ts +16 -21
- package/src/runtime/streaming-ssr.ts +24 -33
- package/src/runtime/trace.ts +144 -144
- package/src/seo/index.ts +214 -214
- package/src/seo/integration/ssr.ts +307 -307
- package/src/seo/render/basic.ts +427 -427
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +191 -191
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +126 -126
- package/src/seo/resolve/index.ts +353 -353
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +97 -97
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +575 -575
- package/src/slot/validator.ts +39 -39
- package/src/spec/index.ts +3 -3
- package/src/spec/load.ts +76 -76
- package/src/spec/lock.ts +56 -56
- package/src/utils/bun.ts +8 -8
- package/src/utils/lru-cache.ts +75 -75
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
|
@@ -1,222 +1,222 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mandu Kitchen DevTools - Redaction Worker
|
|
3
|
-
* @version 1.1.0
|
|
4
|
-
*
|
|
5
|
-
* Web Worker for heavy text processing (redaction, truncation)
|
|
6
|
-
* Prevents main thread blocking during large payload processing
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { RedactPattern, WorkerTask } from '../types';
|
|
10
|
-
|
|
11
|
-
// ============================================================================
|
|
12
|
-
// Worker Message Types
|
|
13
|
-
// ============================================================================
|
|
14
|
-
|
|
15
|
-
export interface WorkerRequest {
|
|
16
|
-
id: string;
|
|
17
|
-
type: 'redact' | 'truncate' | 'ping';
|
|
18
|
-
data: {
|
|
19
|
-
text?: string;
|
|
20
|
-
patterns?: RedactPattern[];
|
|
21
|
-
maxBytes?: number;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface WorkerResponse {
|
|
26
|
-
id: string;
|
|
27
|
-
success: boolean;
|
|
28
|
-
result?: string;
|
|
29
|
-
error?: string;
|
|
30
|
-
timing?: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ============================================================================
|
|
34
|
-
// Redaction Logic (Worker-safe, no DOM dependencies)
|
|
35
|
-
// ============================================================================
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 빌트인 시크릿 패턴
|
|
39
|
-
*/
|
|
40
|
-
const BUILT_IN_SECRET_PATTERNS: RedactPattern[] = [
|
|
41
|
-
// JWT
|
|
42
|
-
{ source: 'eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}', label: 'JWT' },
|
|
43
|
-
// AWS Keys
|
|
44
|
-
{ source: 'AKIA[0-9A-Z]{16}', label: 'AWS_KEY' },
|
|
45
|
-
// Generic API Keys
|
|
46
|
-
{ source: '(?:api[_-]?key|apikey)["\']?\\s*[:=]\\s*["\']?[A-Za-z0-9_-]{20,}', flags: 'i', label: 'API_KEY' },
|
|
47
|
-
// Bearer Tokens
|
|
48
|
-
{ source: 'Bearer\\s+[A-Za-z0-9_-]{20,}', label: 'BEARER' },
|
|
49
|
-
// Generic Secrets
|
|
50
|
-
{ source: '(?:secret|password|passwd|pwd)["\']?\\s*[:=]\\s*["\']?[^\\s"\']{8,}', flags: 'i', label: 'SECRET' },
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* PII 패턴
|
|
55
|
-
*/
|
|
56
|
-
const PII_PATTERNS: RedactPattern[] = [
|
|
57
|
-
// Email
|
|
58
|
-
{ source: '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}', label: 'EMAIL' },
|
|
59
|
-
// Phone (국제)
|
|
60
|
-
{ source: '\\+?[1-9]\\d{1,14}', label: 'PHONE' },
|
|
61
|
-
// IP Address
|
|
62
|
-
{ source: '\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b', label: 'IP' },
|
|
63
|
-
// Credit Card (basic)
|
|
64
|
-
{ source: '\\b(?:\\d{4}[- ]?){3}\\d{4}\\b', label: 'CARD' },
|
|
65
|
-
// SSN (US)
|
|
66
|
-
{ source: '\\b\\d{3}-\\d{2}-\\d{4}\\b', label: 'SSN' },
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 패턴 적용
|
|
71
|
-
*/
|
|
72
|
-
function applyPattern(text: string, pattern: RedactPattern): string {
|
|
73
|
-
try {
|
|
74
|
-
const regex = new RegExp(pattern.source, pattern.flags ?? 'g');
|
|
75
|
-
const replacement = pattern.replacement ?? `[${pattern.label ?? 'REDACTED'}]`;
|
|
76
|
-
return text.replace(regex, replacement);
|
|
77
|
-
} catch {
|
|
78
|
-
// 잘못된 정규식은 무시
|
|
79
|
-
return text;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 텍스트 리댁션
|
|
85
|
-
*/
|
|
86
|
-
function redactText(
|
|
87
|
-
text: string,
|
|
88
|
-
customPatterns: RedactPattern[] = [],
|
|
89
|
-
options: { applyBuiltIn?: boolean; applyPII?: boolean } = {}
|
|
90
|
-
): string {
|
|
91
|
-
const { applyBuiltIn = true, applyPII = true } = options;
|
|
92
|
-
|
|
93
|
-
let result = text;
|
|
94
|
-
|
|
95
|
-
// 빌트인 시크릿 패턴 적용
|
|
96
|
-
if (applyBuiltIn) {
|
|
97
|
-
for (const pattern of BUILT_IN_SECRET_PATTERNS) {
|
|
98
|
-
result = applyPattern(result, pattern);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// PII 패턴 적용
|
|
103
|
-
if (applyPII) {
|
|
104
|
-
for (const pattern of PII_PATTERNS) {
|
|
105
|
-
result = applyPattern(result, pattern);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// 커스텀 패턴 적용
|
|
110
|
-
for (const pattern of customPatterns) {
|
|
111
|
-
result = applyPattern(result, pattern);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* 텍스트 truncation (UTF-8 바이트 기준)
|
|
119
|
-
*/
|
|
120
|
-
function truncateText(text: string, maxBytes: number): string {
|
|
121
|
-
const encoder = new TextEncoder();
|
|
122
|
-
const bytes = encoder.encode(text);
|
|
123
|
-
|
|
124
|
-
if (bytes.length <= maxBytes) {
|
|
125
|
-
return text;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 바이트 제한에 맞게 자르기 (UTF-8 경계 고려)
|
|
129
|
-
let truncatedBytes = bytes.slice(0, maxBytes - 3); // '...' 공간 확보
|
|
130
|
-
|
|
131
|
-
// UTF-8 멀티바이트 문자 경계 맞추기
|
|
132
|
-
while (truncatedBytes.length > 0) {
|
|
133
|
-
const lastByte = truncatedBytes[truncatedBytes.length - 1];
|
|
134
|
-
// 멀티바이트 문자의 중간 바이트인지 확인 (10xxxxxx 패턴)
|
|
135
|
-
if ((lastByte & 0xc0) === 0x80) {
|
|
136
|
-
truncatedBytes = truncatedBytes.slice(0, -1);
|
|
137
|
-
} else {
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const decoder = new TextDecoder();
|
|
143
|
-
return decoder.decode(truncatedBytes) + '...';
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ============================================================================
|
|
147
|
-
// Worker Entry Point
|
|
148
|
-
// ============================================================================
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Worker 메시지 핸들러
|
|
152
|
-
*/
|
|
153
|
-
function handleMessage(request: WorkerRequest): WorkerResponse {
|
|
154
|
-
const startTime = performance.now();
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
switch (request.type) {
|
|
158
|
-
case 'ping':
|
|
159
|
-
return {
|
|
160
|
-
id: request.id,
|
|
161
|
-
success: true,
|
|
162
|
-
result: 'pong',
|
|
163
|
-
timing: performance.now() - startTime,
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
case 'redact': {
|
|
167
|
-
const { text = '', patterns = [] } = request.data;
|
|
168
|
-
const result = redactText(text, patterns);
|
|
169
|
-
return {
|
|
170
|
-
id: request.id,
|
|
171
|
-
success: true,
|
|
172
|
-
result,
|
|
173
|
-
timing: performance.now() - startTime,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
case 'truncate': {
|
|
178
|
-
const { text = '', maxBytes = 10000 } = request.data;
|
|
179
|
-
const result = truncateText(text, maxBytes);
|
|
180
|
-
return {
|
|
181
|
-
id: request.id,
|
|
182
|
-
success: true,
|
|
183
|
-
result,
|
|
184
|
-
timing: performance.now() - startTime,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
default:
|
|
189
|
-
return {
|
|
190
|
-
id: request.id,
|
|
191
|
-
success: false,
|
|
192
|
-
error: `Unknown request type: ${(request as any).type}`,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
} catch (error) {
|
|
196
|
-
return {
|
|
197
|
-
id: request.id,
|
|
198
|
-
success: false,
|
|
199
|
-
error: error instanceof Error ? error.message : String(error),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Worker 컨텍스트에서만 실행
|
|
205
|
-
if (typeof self !== 'undefined' && typeof (self as any).postMessage === 'function') {
|
|
206
|
-
self.onmessage = (event: MessageEvent<WorkerRequest>) => {
|
|
207
|
-
const response = handleMessage(event.data);
|
|
208
|
-
(self as any).postMessage(response);
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// ============================================================================
|
|
213
|
-
// Exports for testing / main-thread fallback
|
|
214
|
-
// ============================================================================
|
|
215
|
-
|
|
216
|
-
export {
|
|
217
|
-
redactText,
|
|
218
|
-
truncateText,
|
|
219
|
-
handleMessage,
|
|
220
|
-
BUILT_IN_SECRET_PATTERNS,
|
|
221
|
-
PII_PATTERNS,
|
|
222
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Mandu Kitchen DevTools - Redaction Worker
|
|
3
|
+
* @version 1.1.0
|
|
4
|
+
*
|
|
5
|
+
* Web Worker for heavy text processing (redaction, truncation)
|
|
6
|
+
* Prevents main thread blocking during large payload processing
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { RedactPattern, WorkerTask } from '../types';
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Worker Message Types
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
export interface WorkerRequest {
|
|
16
|
+
id: string;
|
|
17
|
+
type: 'redact' | 'truncate' | 'ping';
|
|
18
|
+
data: {
|
|
19
|
+
text?: string;
|
|
20
|
+
patterns?: RedactPattern[];
|
|
21
|
+
maxBytes?: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WorkerResponse {
|
|
26
|
+
id: string;
|
|
27
|
+
success: boolean;
|
|
28
|
+
result?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
timing?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Redaction Logic (Worker-safe, no DOM dependencies)
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 빌트인 시크릿 패턴
|
|
39
|
+
*/
|
|
40
|
+
const BUILT_IN_SECRET_PATTERNS: RedactPattern[] = [
|
|
41
|
+
// JWT
|
|
42
|
+
{ source: 'eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}', label: 'JWT' },
|
|
43
|
+
// AWS Keys
|
|
44
|
+
{ source: 'AKIA[0-9A-Z]{16}', label: 'AWS_KEY' },
|
|
45
|
+
// Generic API Keys
|
|
46
|
+
{ source: '(?:api[_-]?key|apikey)["\']?\\s*[:=]\\s*["\']?[A-Za-z0-9_-]{20,}', flags: 'i', label: 'API_KEY' },
|
|
47
|
+
// Bearer Tokens
|
|
48
|
+
{ source: 'Bearer\\s+[A-Za-z0-9_-]{20,}', label: 'BEARER' },
|
|
49
|
+
// Generic Secrets
|
|
50
|
+
{ source: '(?:secret|password|passwd|pwd)["\']?\\s*[:=]\\s*["\']?[^\\s"\']{8,}', flags: 'i', label: 'SECRET' },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* PII 패턴
|
|
55
|
+
*/
|
|
56
|
+
const PII_PATTERNS: RedactPattern[] = [
|
|
57
|
+
// Email
|
|
58
|
+
{ source: '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}', label: 'EMAIL' },
|
|
59
|
+
// Phone (국제)
|
|
60
|
+
{ source: '\\+?[1-9]\\d{1,14}', label: 'PHONE' },
|
|
61
|
+
// IP Address
|
|
62
|
+
{ source: '\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b', label: 'IP' },
|
|
63
|
+
// Credit Card (basic)
|
|
64
|
+
{ source: '\\b(?:\\d{4}[- ]?){3}\\d{4}\\b', label: 'CARD' },
|
|
65
|
+
// SSN (US)
|
|
66
|
+
{ source: '\\b\\d{3}-\\d{2}-\\d{4}\\b', label: 'SSN' },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 패턴 적용
|
|
71
|
+
*/
|
|
72
|
+
function applyPattern(text: string, pattern: RedactPattern): string {
|
|
73
|
+
try {
|
|
74
|
+
const regex = new RegExp(pattern.source, pattern.flags ?? 'g');
|
|
75
|
+
const replacement = pattern.replacement ?? `[${pattern.label ?? 'REDACTED'}]`;
|
|
76
|
+
return text.replace(regex, replacement);
|
|
77
|
+
} catch {
|
|
78
|
+
// 잘못된 정규식은 무시
|
|
79
|
+
return text;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 텍스트 리댁션
|
|
85
|
+
*/
|
|
86
|
+
function redactText(
|
|
87
|
+
text: string,
|
|
88
|
+
customPatterns: RedactPattern[] = [],
|
|
89
|
+
options: { applyBuiltIn?: boolean; applyPII?: boolean } = {}
|
|
90
|
+
): string {
|
|
91
|
+
const { applyBuiltIn = true, applyPII = true } = options;
|
|
92
|
+
|
|
93
|
+
let result = text;
|
|
94
|
+
|
|
95
|
+
// 빌트인 시크릿 패턴 적용
|
|
96
|
+
if (applyBuiltIn) {
|
|
97
|
+
for (const pattern of BUILT_IN_SECRET_PATTERNS) {
|
|
98
|
+
result = applyPattern(result, pattern);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// PII 패턴 적용
|
|
103
|
+
if (applyPII) {
|
|
104
|
+
for (const pattern of PII_PATTERNS) {
|
|
105
|
+
result = applyPattern(result, pattern);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 커스텀 패턴 적용
|
|
110
|
+
for (const pattern of customPatterns) {
|
|
111
|
+
result = applyPattern(result, pattern);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 텍스트 truncation (UTF-8 바이트 기준)
|
|
119
|
+
*/
|
|
120
|
+
function truncateText(text: string, maxBytes: number): string {
|
|
121
|
+
const encoder = new TextEncoder();
|
|
122
|
+
const bytes = encoder.encode(text);
|
|
123
|
+
|
|
124
|
+
if (bytes.length <= maxBytes) {
|
|
125
|
+
return text;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 바이트 제한에 맞게 자르기 (UTF-8 경계 고려)
|
|
129
|
+
let truncatedBytes = bytes.slice(0, maxBytes - 3); // '...' 공간 확보
|
|
130
|
+
|
|
131
|
+
// UTF-8 멀티바이트 문자 경계 맞추기
|
|
132
|
+
while (truncatedBytes.length > 0) {
|
|
133
|
+
const lastByte = truncatedBytes[truncatedBytes.length - 1];
|
|
134
|
+
// 멀티바이트 문자의 중간 바이트인지 확인 (10xxxxxx 패턴)
|
|
135
|
+
if ((lastByte & 0xc0) === 0x80) {
|
|
136
|
+
truncatedBytes = truncatedBytes.slice(0, -1);
|
|
137
|
+
} else {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const decoder = new TextDecoder();
|
|
143
|
+
return decoder.decode(truncatedBytes) + '...';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Worker Entry Point
|
|
148
|
+
// ============================================================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Worker 메시지 핸들러
|
|
152
|
+
*/
|
|
153
|
+
function handleMessage(request: WorkerRequest): WorkerResponse {
|
|
154
|
+
const startTime = performance.now();
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
switch (request.type) {
|
|
158
|
+
case 'ping':
|
|
159
|
+
return {
|
|
160
|
+
id: request.id,
|
|
161
|
+
success: true,
|
|
162
|
+
result: 'pong',
|
|
163
|
+
timing: performance.now() - startTime,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
case 'redact': {
|
|
167
|
+
const { text = '', patterns = [] } = request.data;
|
|
168
|
+
const result = redactText(text, patterns);
|
|
169
|
+
return {
|
|
170
|
+
id: request.id,
|
|
171
|
+
success: true,
|
|
172
|
+
result,
|
|
173
|
+
timing: performance.now() - startTime,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
case 'truncate': {
|
|
178
|
+
const { text = '', maxBytes = 10000 } = request.data;
|
|
179
|
+
const result = truncateText(text, maxBytes);
|
|
180
|
+
return {
|
|
181
|
+
id: request.id,
|
|
182
|
+
success: true,
|
|
183
|
+
result,
|
|
184
|
+
timing: performance.now() - startTime,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
default:
|
|
189
|
+
return {
|
|
190
|
+
id: request.id,
|
|
191
|
+
success: false,
|
|
192
|
+
error: `Unknown request type: ${(request as any).type}`,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return {
|
|
197
|
+
id: request.id,
|
|
198
|
+
success: false,
|
|
199
|
+
error: error instanceof Error ? error.message : String(error),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Worker 컨텍스트에서만 실행
|
|
205
|
+
if (typeof self !== 'undefined' && typeof (self as any).postMessage === 'function') {
|
|
206
|
+
self.onmessage = (event: MessageEvent<WorkerRequest>) => {
|
|
207
|
+
const response = handleMessage(event.data);
|
|
208
|
+
(self as any).postMessage(response);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// Exports for testing / main-thread fallback
|
|
214
|
+
// ============================================================================
|
|
215
|
+
|
|
216
|
+
export {
|
|
217
|
+
redactText,
|
|
218
|
+
truncateText,
|
|
219
|
+
handleMessage,
|
|
220
|
+
BUILT_IN_SECRET_PATTERNS,
|
|
221
|
+
PII_PATTERNS,
|
|
222
|
+
};
|