@ddunigma/node 2.2.0 → 3.0.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/README.md +171 -312
- package/dist/DduStream-NP3CMCKK.js +2 -0
- package/dist/chunk-FVBZKVPE.js +4 -0
- package/dist/index.cjs +5 -6
- package/dist/index.d.cts +65 -94
- package/dist/index.d.ts +65 -94
- package/dist/index.js +4 -4
- package/package.json +8 -3
- package/dist/DduStream-KO75MEEM.js +0 -2
- package/dist/chunk-CZMUPXSK.js +0 -5
package/README.md
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
# ddunigma Node
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@ddunigma/node)
|
|
4
4
|
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
Node.js implementation of [ddunigma](https://github.com/i3l3/ddunigma) (Python original)
|
|
8
|
-
|
|
9
5
|
커스텀 charset을 사용하는 Base64 스타일 인코더/디코더 라이브러리입니다.
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- `README.md`: 설치, 사용법, 공개 API 요약
|
|
14
|
-
- `CHANGELOG.md`: 공개 변경 이력
|
|
15
|
-
- `RELEASE.md`: 배포 체크리스트와 릴리즈 기준
|
|
7
|
+
V2 추가사항
|
|
16
8
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- Original Python Implementation by:
|
|
20
|
-
- [@i3ls](https://github.com/i3l3)
|
|
21
|
-
- [@gunu3371](https://github.com/gunu3371)
|
|
22
|
-
- Original Repository: [ddunigma](https://github.com/i3l3/ddunigma)
|
|
9
|
+
- 이제 한글 종성 결합 시스템을 활용하여 8개 기본 문자 × 8개 종성으로 64가지 조합을 만들어, 6비트를 한 글자로 표현합니다.
|
|
23
10
|
|
|
24
11
|
## Requirements
|
|
25
12
|
|
|
26
13
|
- **Node.js >= 18.0.0**
|
|
27
|
-
- 라이브러리는 `ES2022` 타깃으로 빌드되며, 현재 스트림 암호화/압축 조합은 Node 18+ 기준으로 검증됩니다.
|
|
28
14
|
|
|
29
15
|
## Install
|
|
30
16
|
|
|
@@ -32,223 +18,195 @@ Node.js implementation of [ddunigma](https://github.com/i3l3/ddunigma) (Python o
|
|
|
32
18
|
npm install @ddunigma/node
|
|
33
19
|
```
|
|
34
20
|
|
|
35
|
-
##
|
|
36
|
-
|
|
37
|
-
### 기본 인코딩/디코딩
|
|
21
|
+
## Quick Start
|
|
38
22
|
|
|
39
23
|
```typescript
|
|
40
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
41
|
-
|
|
42
|
-
// 커스텀 charset으로 인코더 생성
|
|
43
|
-
const encoder = new Ddu64("우따야", "뭐");
|
|
24
|
+
import { Ddu64, DduSetSymbol } from "@ddunigma/node";
|
|
44
25
|
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
26
|
+
// V2 (기본, 한글 종성 결합 64개)
|
|
27
|
+
const ddu = new Ddu64();
|
|
28
|
+
ddu.encode("안녕하세요"); // "뎯땩잇땨뎪뎨잇잉뎯욱잇우뎯땨읶뎨뎯땩듂잊"
|
|
29
|
+
ddu.decode("뎯땩잇땨뎪뎨잇잉뎯욱잇우뎯땨읶뎨뎯땩듂잊"); // "안녕하세요"
|
|
48
30
|
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
// V1 (구버전 호환, 8개 문자 쌍 방식)
|
|
32
|
+
const dduV1 = new Ddu64(undefined, undefined, { dduSetSymbol: DduSetSymbol.DDU_V1 });
|
|
33
|
+
dduV1.encode("안녕하세요"); // ".우땨땨이?땨뜌.이.뜌이?이!.우우땨이?우뜌.우땨뜌이이.뜌.우땨땨!이이야"
|
|
34
|
+
dduV1.decode(".우땨땨이?땨뜌.이.뜌이?이!.우우땨이?우뜌.우땨뜌이이.뜌.우땨땨!이이야"); // "안녕하세요"
|
|
51
35
|
```
|
|
52
36
|
|
|
53
|
-
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 기본 사용법
|
|
40
|
+
|
|
41
|
+
### 인코딩/디코딩
|
|
54
42
|
|
|
55
43
|
```typescript
|
|
56
|
-
import { Ddu64
|
|
44
|
+
import { Ddu64 } from "@ddunigma/node";
|
|
57
45
|
|
|
58
|
-
|
|
59
|
-
const encoder1 = new Ddu64(undefined, undefined, {
|
|
60
|
-
dduSetSymbol: DduSetSymbol.ONECHARSET,
|
|
61
|
-
});
|
|
46
|
+
const encoder = new Ddu64();
|
|
62
47
|
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
});
|
|
48
|
+
const encoded = encoder.encode("Hello World!");
|
|
49
|
+
const decoded = encoder.decode(encoded);
|
|
50
|
+
```
|
|
67
51
|
|
|
68
|
-
|
|
69
|
-
const encoder3 = new Ddu64(undefined, undefined, {
|
|
70
|
-
dduSetSymbol: DduSetSymbol.TWOCHARSET,
|
|
71
|
-
});
|
|
52
|
+
### 커스텀 charset
|
|
72
53
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
54
|
+
```typescript
|
|
55
|
+
// 문자열 또는 배열로 charset 지정
|
|
56
|
+
const encoder = new Ddu64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "=");
|
|
77
57
|
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
58
|
+
// 종성 결합 커스텀 charset (dduChar × codaChar 동적 생성)
|
|
59
|
+
const encoder2 = new Ddu64(["가", "나", "다", "라"], "뭐", {
|
|
60
|
+
codaChar: ["", "ㄱ", "ㄲ", "ㄷ"], // 4×4 = 16개 조합
|
|
61
|
+
});
|
|
81
62
|
```
|
|
82
63
|
|
|
83
|
-
###
|
|
64
|
+
### 프리셋
|
|
65
|
+
|
|
66
|
+
| Symbol | 문자 수 | 비트 | 설명 |
|
|
67
|
+
| ------------ | ------- | ---- | ------------------------------------ |
|
|
68
|
+
| `DDU` | 64 | 6 | 한글 종성 결합 (8 기본문자 × 8 종성) |
|
|
69
|
+
| `DDU_V1` | 8 | 3 | 구버전 호환 (뜌땨이우야!?.) |
|
|
70
|
+
| `ONECHARSET` | 64 | 6 | 영문 + 숫자 + 특수문자 |
|
|
84
71
|
|
|
85
72
|
```typescript
|
|
86
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
73
|
+
import { Ddu64, DduSetSymbol } from "@ddunigma/node";
|
|
87
74
|
|
|
88
|
-
// 생성자에서 기본 압축 활성화
|
|
89
75
|
const encoder = new Ddu64(undefined, undefined, {
|
|
90
|
-
|
|
76
|
+
dduSetSymbol: DduSetSymbol.ONECHARSET,
|
|
91
77
|
});
|
|
92
|
-
|
|
93
|
-
// 또는 encode 호출 시 압축 옵션 지정
|
|
94
|
-
const text = "반복되는 긴 텍스트...".repeat(100);
|
|
95
|
-
const encoded = encoder.encode(text, { compress: true });
|
|
96
|
-
const decoded = encoder.decode(encoded); // 자동으로 압축 해제
|
|
97
78
|
```
|
|
98
79
|
|
|
99
|
-
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 고급 기능
|
|
83
|
+
|
|
84
|
+
### 압축
|
|
85
|
+
|
|
86
|
+
deflate(기본) 또는 brotli 압축을 지원합니다. 디코딩 시 자동으로 압축 여부를 감지합니다.
|
|
100
87
|
|
|
101
88
|
```typescript
|
|
102
|
-
|
|
89
|
+
const encoder = new Ddu64();
|
|
103
90
|
|
|
104
|
-
|
|
91
|
+
// 호출 시 옵션으로 지정
|
|
92
|
+
const encoded = encoder.encode(longText, { compress: true });
|
|
93
|
+
const decoded = encoder.decode(encoded);
|
|
105
94
|
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
// 생성자에서 기본 활성화
|
|
96
|
+
const compressEncoder = new Ddu64(undefined, undefined, {
|
|
97
|
+
compress: true,
|
|
98
|
+
compressionAlgorithm: "brotli",
|
|
99
|
+
compressionLevel: 6,
|
|
108
100
|
});
|
|
109
|
-
|
|
110
|
-
const encoded = encoder.encode("Hello World!");
|
|
111
|
-
// URL에서 안전하게 사용 가능한 문자열 반환
|
|
112
101
|
```
|
|
113
102
|
|
|
114
|
-
|
|
103
|
+
### 암호화
|
|
115
104
|
|
|
116
|
-
|
|
105
|
+
AES-256-GCM 암호화를 내장합니다. 동일한 키로 생성된 인코더만 복호화할 수 있습니다.
|
|
117
106
|
|
|
118
107
|
```typescript
|
|
119
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
120
|
-
|
|
121
108
|
const encoder = new Ddu64(undefined, undefined, {
|
|
122
|
-
|
|
109
|
+
encryptionKey: "my-secret-key",
|
|
123
110
|
});
|
|
124
111
|
|
|
125
|
-
const encoded = encoder.encode("
|
|
126
|
-
const decoded = encoder.decode(encoded);
|
|
127
|
-
// 체크섬 불일치 시 에러 발생
|
|
112
|
+
const encoded = encoder.encode("비밀 메시지");
|
|
113
|
+
const decoded = encoder.decode(encoded);
|
|
128
114
|
```
|
|
129
115
|
|
|
130
|
-
###
|
|
116
|
+
### 체크섬
|
|
117
|
+
|
|
118
|
+
CRC32 체크섬으로 데이터 무결성을 검증합니다.
|
|
131
119
|
|
|
132
120
|
```typescript
|
|
133
|
-
|
|
121
|
+
const encoder = new Ddu64();
|
|
134
122
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
const encoded = encoder.encode(data, { checksum: true });
|
|
124
|
+
const decoded = encoder.decode(encoded, { checksum: true });
|
|
125
|
+
// 데이터 변조 시 에러 발생
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### URL-Safe
|
|
138
129
|
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
`+`, `/`, `=` 를 URL 안전 문자(`-`, `_`, `.`)로 변환합니다.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const encoder = new Ddu64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "=", {
|
|
134
|
+
urlSafe: true,
|
|
135
|
+
});
|
|
141
136
|
```
|
|
142
137
|
|
|
138
|
+
> charset/padding에 `-`, `_`, `.` 가 포함되면 urlSafe를 활성화할 수 없습니다.
|
|
139
|
+
|
|
143
140
|
### 청크 분할
|
|
144
141
|
|
|
145
142
|
```typescript
|
|
146
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
147
|
-
|
|
148
143
|
const encoder = new Ddu64();
|
|
149
144
|
|
|
150
|
-
const encoded = encoder.encode(
|
|
151
|
-
chunkSize: 76,
|
|
152
|
-
chunkSeparator: "\n",
|
|
145
|
+
const encoded = encoder.encode(data, {
|
|
146
|
+
chunkSize: 76,
|
|
147
|
+
chunkSeparator: "\n",
|
|
153
148
|
});
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
const decoded = encoder.decode(encoded); // 자동으로 줄바꿈 제거
|
|
149
|
+
// 디코딩 시 구분자 자동 제거
|
|
157
150
|
```
|
|
158
151
|
|
|
159
|
-
### 비동기
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
152
|
+
### 비동기 처리
|
|
163
153
|
|
|
164
|
-
|
|
154
|
+
대용량 데이터에서 이벤트 루프 블로킹을 방지합니다.
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
const encoded = await encoder.encodeAsync(
|
|
156
|
+
```typescript
|
|
157
|
+
const encoded = await encoder.encodeAsync(largeBuffer);
|
|
168
158
|
const decoded = await encoder.decodeAsync(encoded);
|
|
169
159
|
const buffer = await encoder.decodeToBufferAsync(encoded);
|
|
170
160
|
```
|
|
171
161
|
|
|
172
|
-
큰 입력에서 기본 경로는 이벤트 루프에 양보하면서 처리합니다. 다만 압축, 암호화, 체크섬, URL-safe 같은 옵션이 함께 켜진 복합 경로는 안전성을 위해 전체 payload 기준 fallback을 사용할 수 있습니다.
|
|
173
|
-
|
|
174
162
|
### 진행률 콜백
|
|
175
163
|
|
|
176
164
|
```typescript
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
encoder.encode(largeData, {
|
|
182
|
-
onProgress: (info) => {
|
|
183
|
-
console.log(`진행률: ${info.percent}%`);
|
|
184
|
-
console.log(`처리됨: ${info.processedBytes}/${info.totalBytes}`);
|
|
165
|
+
encoder.encode(data, {
|
|
166
|
+
onProgress: ({ percent, stage }) => {
|
|
167
|
+
console.log(`${percent}% (${stage})`);
|
|
185
168
|
},
|
|
186
169
|
});
|
|
187
170
|
```
|
|
188
171
|
|
|
189
|
-
###
|
|
172
|
+
### 통계
|
|
190
173
|
|
|
191
174
|
```typescript
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const encoder = new Ddu64();
|
|
195
|
-
|
|
196
|
-
const stats = encoder.getStats("Test data", { compress: true });
|
|
197
|
-
console.log(stats);
|
|
198
|
-
// {
|
|
199
|
-
// originalSize: 9,
|
|
200
|
-
// encodedSize: 12,
|
|
201
|
-
// compressedSize: 17,
|
|
202
|
-
// compressionRatio: 1.89,
|
|
203
|
-
// expansionRatio: 1.33,
|
|
204
|
-
// charsetSize: 64,
|
|
205
|
-
// bitLength: 6
|
|
206
|
-
// }
|
|
175
|
+
const stats = encoder.getStats(data, { compress: true });
|
|
176
|
+
// { originalSize, encodedSize, compressedSize, compressionRatio, expansionRatio, charsetSize, bitLength }
|
|
207
177
|
```
|
|
208
178
|
|
|
209
179
|
### Zip Bomb 방어
|
|
210
180
|
|
|
211
181
|
```typescript
|
|
212
|
-
import { Ddu64 } from "@ddunigma/node";
|
|
213
|
-
|
|
214
182
|
const encoder = new Ddu64(undefined, undefined, {
|
|
215
183
|
maxDecodedBytes: 10 * 1024 * 1024, // 10MB
|
|
216
184
|
maxDecompressedBytes: 50 * 1024 * 1024, // 50MB
|
|
217
185
|
});
|
|
218
|
-
|
|
219
|
-
// 제한 초과 시 에러 발생
|
|
220
186
|
```
|
|
221
187
|
|
|
222
188
|
---
|
|
223
189
|
|
|
224
190
|
## CharsetBuilder
|
|
225
191
|
|
|
226
|
-
커스텀 charset을
|
|
192
|
+
커스텀 charset을 빌더 패턴으로 생성합니다.
|
|
227
193
|
|
|
228
194
|
```typescript
|
|
229
195
|
import { CharsetBuilder } from "@ddunigma/node";
|
|
230
196
|
|
|
231
|
-
// 유니코드
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
// Base64 문자셋
|
|
235
|
-
const chars2 = CharsetBuilder.base64().build();
|
|
197
|
+
// 유니코드 범위
|
|
198
|
+
CharsetBuilder.fromUnicodeRange(0x4e00, 0x4e3f).build();
|
|
236
199
|
|
|
237
|
-
// 혼동 문자 제외
|
|
238
|
-
|
|
200
|
+
// Base64에서 혼동 문자 제외
|
|
201
|
+
CharsetBuilder.base64().excludeConfusing().build();
|
|
239
202
|
|
|
240
|
-
// 2의 제곱수로 제한
|
|
241
|
-
|
|
203
|
+
// 2의 제곱수로 제한 + 시드 셔플
|
|
204
|
+
CharsetBuilder.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
242
205
|
.limitToPowerOfTwo()
|
|
243
|
-
.
|
|
244
|
-
|
|
245
|
-
// URL 안전 문자만
|
|
246
|
-
const chars5 = CharsetBuilder.base64().excludeUrlUnsafe().build();
|
|
206
|
+
.shuffle(12345)
|
|
207
|
+
.build();
|
|
247
208
|
|
|
248
|
-
//
|
|
249
|
-
const chars6 = CharsetBuilder.base64().shuffle(12345).build();
|
|
250
|
-
|
|
251
|
-
// 패딩 문자와 함께 빌드
|
|
209
|
+
// 패딩 문자 자동 선택
|
|
252
210
|
const { charset, padding } = CharsetBuilder.base64().buildWithPadding();
|
|
253
211
|
```
|
|
254
212
|
|
|
@@ -256,226 +214,127 @@ const { charset, padding } = CharsetBuilder.base64().buildWithPadding();
|
|
|
256
214
|
|
|
257
215
|
## DduPipeline
|
|
258
216
|
|
|
259
|
-
|
|
217
|
+
압축 → 암호화 → 인코딩을 체이닝하고, `reverse()`로 역순 복원합니다.
|
|
260
218
|
|
|
261
219
|
```typescript
|
|
262
220
|
import { DduPipeline, Ddu64 } from "@ddunigma/node";
|
|
263
221
|
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
// 압축 → 암호화 → 인코딩 파이프라인
|
|
267
|
-
const pipeline = new DduPipeline()
|
|
268
|
-
.compress(6, "brotli")
|
|
269
|
-
.encrypt("my-secret-key")
|
|
270
|
-
.encode(encoder);
|
|
271
|
-
|
|
272
|
-
const encoded = pipeline.processToString("Hello World!");
|
|
222
|
+
const pipeline = new DduPipeline().compress(6, "brotli").encrypt("secret-key").encode(new Ddu64());
|
|
273
223
|
|
|
274
|
-
|
|
224
|
+
const encoded = pipeline.processToString("Hello");
|
|
275
225
|
const decoded = pipeline.reverse().processToString(encoded);
|
|
276
226
|
```
|
|
277
227
|
|
|
278
228
|
---
|
|
279
229
|
|
|
280
|
-
## 스트림
|
|
230
|
+
## 스트림
|
|
281
231
|
|
|
282
|
-
대용량
|
|
232
|
+
대용량 파일을 메모리 효율적으로 처리합니다. 스트림 헤더로 압축/암호화를 자동 감지합니다.
|
|
283
233
|
|
|
284
234
|
```typescript
|
|
285
235
|
import { Ddu64, createEncodeStream, createDecodeStream } from "@ddunigma/node";
|
|
286
236
|
import fs from "fs";
|
|
287
237
|
|
|
288
|
-
const encoder = new Ddu64();
|
|
289
|
-
|
|
290
|
-
// 인코딩 스트림
|
|
291
|
-
fs.createReadStream("input.bin")
|
|
292
|
-
.pipe(createEncodeStream(encoder))
|
|
293
|
-
.pipe(fs.createWriteStream("output.txt"));
|
|
294
|
-
|
|
295
|
-
// 디코딩 스트림
|
|
296
|
-
fs.createReadStream("output.txt")
|
|
297
|
-
.pipe(createDecodeStream(encoder))
|
|
298
|
-
.pipe(fs.createWriteStream("restored.bin"));
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
압축과 암호화를 함께 사용하는 스트림도 바로 연결할 수 있습니다.
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
import { Ddu64, DduSetSymbol, createEncodeStream, createDecodeStream } from "@ddunigma/node";
|
|
305
|
-
import fs from "fs";
|
|
306
|
-
|
|
307
238
|
const encoder = new Ddu64(undefined, undefined, {
|
|
308
|
-
dduSetSymbol: DduSetSymbol.ONECHARSET,
|
|
309
239
|
compress: true,
|
|
310
|
-
|
|
311
|
-
encryptionKey: "stream-secret-key",
|
|
240
|
+
encryptionKey: "stream-key",
|
|
312
241
|
});
|
|
313
242
|
|
|
314
|
-
fs.createReadStream("input.
|
|
243
|
+
fs.createReadStream("input.bin")
|
|
315
244
|
.pipe(createEncodeStream(encoder))
|
|
316
|
-
.pipe(fs.createWriteStream("
|
|
245
|
+
.pipe(fs.createWriteStream("output.ddu"));
|
|
317
246
|
|
|
318
|
-
fs.createReadStream("
|
|
247
|
+
fs.createReadStream("output.ddu")
|
|
319
248
|
.pipe(createDecodeStream(encoder))
|
|
320
|
-
.pipe(fs.createWriteStream("
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
기본 `createEncodeStream()` 은 작은 스트림 헤더를 함께 기록하고, 기본 `createDecodeStream()` 은 이 헤더를 읽어 압축/암호화 설정을 초기에 auto-detect 합니다. 그래서 기본 경로도 조기 스트리밍 복원이 가능합니다. 암호화된 payload는 동일한 `encryptionKey`가 필요합니다.
|
|
324
|
-
|
|
325
|
-
기존 footer-only 스트림 payload도 계속 디코드됩니다. 다만 과거 포맷은 디코드 쪽에서 전체 payload를 버퍼링할 수 있습니다.
|
|
326
|
-
|
|
327
|
-
헤더 없이 명시적 설정만으로 encode/decode 하려면 양쪽 모두에서 `streamAutoDetect: false` 와 함께 동일한 `compress`, `compressionAlgorithm`, `encryptionKey` 설정을 맞춰 주세요.
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
|
-
## Benchmark
|
|
332
|
-
|
|
333
|
-
대표 시나리오 기준으로 인코딩/디코딩 시간과 샘플링 기반 peak heap 변화를 확인할 수 있습니다.
|
|
334
|
-
|
|
335
|
-
```bash
|
|
336
|
-
pnpm bench
|
|
249
|
+
.pipe(fs.createWriteStream("restored.bin"));
|
|
337
250
|
```
|
|
338
251
|
|
|
339
|
-
벤치마크는 `--expose-gc`로 실행되며, 일반 인코딩, 청크 인코딩, 압축, 암호화 비동기 경로, 공개 스트림 API 조합을 함께 측정합니다.
|
|
340
|
-
|
|
341
|
-
샘플링 기반 측정이므로 profiler 수준의 정확한 peak memory는 아니며, 긴 동기 CPU 구간에서는 실제 피크보다 낮게 보일 수 있습니다.
|
|
342
|
-
|
|
343
252
|
---
|
|
344
253
|
|
|
345
254
|
## API Reference
|
|
346
255
|
|
|
347
256
|
### `new Ddu64(dduChar?, paddingChar?, options?)`
|
|
348
257
|
|
|
349
|
-
인코더 인스턴스를 생성합니다.
|
|
350
|
-
|
|
351
|
-
**Parameters:**
|
|
352
|
-
|
|
353
258
|
| Parameter | Type | Description |
|
|
354
259
|
| ------------- | ----------------------- | ------------------------ |
|
|
355
260
|
| `dduChar` | `string \| string[]` | charset 문자열 또는 배열 |
|
|
356
261
|
| `paddingChar` | `string` | 패딩 문자 |
|
|
357
262
|
| `options` | `DduConstructorOptions` | 옵션 객체 |
|
|
358
263
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
| Option | Type
|
|
362
|
-
| ---------------------- |
|
|
363
|
-
| `dduSetSymbol` | `DduSetSymbol`
|
|
364
|
-
| `
|
|
365
|
-
| `
|
|
366
|
-
| `
|
|
367
|
-
| `
|
|
368
|
-
| `
|
|
369
|
-
| `
|
|
370
|
-
| `
|
|
371
|
-
| `
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
377
|
-
| `
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
|
388
|
-
|
|
|
389
|
-
| `
|
|
390
|
-
| `
|
|
391
|
-
| `
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
|
396
|
-
|
|
|
397
|
-
| `
|
|
398
|
-
| `
|
|
399
|
-
|
|
400
|
-
`
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
### `decodeToBuffer(encoded, options?): Buffer`
|
|
407
|
-
|
|
408
|
-
인코딩된 문자열을 Buffer로 직접 디코딩합니다.
|
|
409
|
-
|
|
410
|
-
### `encodeAsync(data, options?): Promise<string>`
|
|
411
|
-
|
|
412
|
-
비동기로 데이터를 인코딩합니다.
|
|
413
|
-
|
|
414
|
-
### `decodeAsync(encoded, options?): Promise<string>`
|
|
415
|
-
|
|
416
|
-
비동기로 데이터를 디코딩합니다.
|
|
417
|
-
|
|
418
|
-
### `decodeToBufferAsync(encoded, options?): Promise<Buffer>`
|
|
419
|
-
|
|
420
|
-
비동기로 Buffer로 디코딩합니다.
|
|
421
|
-
|
|
422
|
-
### `getStats(data, options?): DduEncodeStats`
|
|
423
|
-
|
|
424
|
-
인코딩 통계 정보를 반환합니다.
|
|
425
|
-
|
|
426
|
-
```typescript
|
|
427
|
-
{
|
|
428
|
-
originalSize: number; // 원본 데이터 크기
|
|
429
|
-
encodedSize: number; // 인코딩된 문자열 길이
|
|
430
|
-
compressedSize?: number; // 압축된 크기
|
|
431
|
-
compressionRatio?: number; // 압축률 (0-1)
|
|
432
|
-
expansionRatio: number; // 인코딩 확장 비율
|
|
433
|
-
charsetSize: number; // charset 크기
|
|
434
|
-
bitLength: number; // 비트 길이
|
|
435
|
-
}
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### `getCharSetInfo(): CharSetInfo`
|
|
439
|
-
|
|
440
|
-
현재 인코더의 charset 정보를 반환합니다.
|
|
441
|
-
|
|
442
|
-
---
|
|
443
|
-
|
|
444
|
-
## DduSetSymbol
|
|
445
|
-
|
|
446
|
-
| Symbol | 문자 수 | 비트 길이 | 설명 |
|
|
447
|
-
| -------------- | ------- | --------- | ------------------------- |
|
|
448
|
-
| `DDU` | 8 | 3 | 한글 + 특수문자 기본 세트 |
|
|
449
|
-
| `ONECHARSET` | 64 | 6 | 영문 + 숫자 + 특수문자 |
|
|
450
|
-
| `TWOCHARSET` | 1024 | 10 | 2글자 조합 세트 |
|
|
451
|
-
| `THREECHARSET` | 32768 | 15 | 3글자 조합 세트 |
|
|
264
|
+
**생성자 옵션:**
|
|
265
|
+
|
|
266
|
+
| Option | Type | Default | Description |
|
|
267
|
+
| ---------------------- | ----------------------- | ----------- | ----------------------------- |
|
|
268
|
+
| `dduSetSymbol` | `DduSetSymbol` | `DDU` | 프리셋 심볼 |
|
|
269
|
+
| `codaChar` | `string[]` | — | 종성 배열 (동적 charset 생성) |
|
|
270
|
+
| `encoding` | `BufferEncoding` | `'utf-8'` | 문자열 인코딩 |
|
|
271
|
+
| `compress` | `boolean` | `false` | 기본 압축 활성화 |
|
|
272
|
+
| `compressionAlgorithm` | `"deflate" \| "brotli"` | `'deflate'` | 압축 알고리즘 |
|
|
273
|
+
| `compressionLevel` | `number` | `6` | 압축 레벨 |
|
|
274
|
+
| `urlSafe` | `boolean` | `false` | URL-Safe 모드 |
|
|
275
|
+
| `encryptionKey` | `string` | — | AES-256-GCM 암호화 키 |
|
|
276
|
+
| `checksum` | `boolean` | `false` | CRC32 체크섬 |
|
|
277
|
+
| `chunkSize` | `number` | — | 청크 분할 크기 |
|
|
278
|
+
| `chunkSeparator` | `string` | `'\n'` | 청크 구분자 |
|
|
279
|
+
| `maxDecodedBytes` | `number` | `67108864` | 최대 디코딩 바이트 (64MB) |
|
|
280
|
+
| `maxDecompressedBytes` | `number` | `67108864` | 최대 압축해제 바이트 (64MB) |
|
|
281
|
+
| `throwOnError` | `boolean` | `false` | 초기화 오류 시 throw |
|
|
282
|
+
| `useRepeatPadding` | `boolean` | `false` | 패딩 문자 반복 방식 |
|
|
283
|
+
| `usePowerOfTwo` | `boolean` | `true` | 2의 제곱수 charset 강제 |
|
|
284
|
+
|
|
285
|
+
**메서드:**
|
|
286
|
+
|
|
287
|
+
| Method | Return | Description |
|
|
288
|
+
| ---------------------------------------- | ----------------- | -------------------- |
|
|
289
|
+
| `encode(data, options?)` | `string` | 인코딩 |
|
|
290
|
+
| `decode(encoded, options?)` | `string` | 디코딩 |
|
|
291
|
+
| `decodeToBuffer(encoded, options?)` | `Buffer` | Buffer로 디코딩 |
|
|
292
|
+
| `encodeAsync(data, options?)` | `Promise<string>` | 비동기 인코딩 |
|
|
293
|
+
| `decodeAsync(encoded, options?)` | `Promise<string>` | 비동기 디코딩 |
|
|
294
|
+
| `decodeToBufferAsync(encoded, options?)` | `Promise<Buffer>` | 비동기 Buffer 디코딩 |
|
|
295
|
+
| `getStats(data, options?)` | `DduEncodeStats` | 인코딩 통계 |
|
|
296
|
+
| `getCharSetInfo()` | `CharSetInfo` | charset 정보 |
|
|
297
|
+
|
|
298
|
+
**encode/decode 옵션 (DduOptions):**
|
|
299
|
+
|
|
300
|
+
| Option | Type | Description |
|
|
301
|
+
| ---------------------- | ----------------------- | -------------------- |
|
|
302
|
+
| `compress` | `boolean` | 압축 사용 |
|
|
303
|
+
| `compressionAlgorithm` | `"deflate" \| "brotli"` | 압축 알고리즘 |
|
|
304
|
+
| `compressionLevel` | `number` | 압축 레벨 |
|
|
305
|
+
| `checksum` | `boolean` | 체크섬 추가/검증 |
|
|
306
|
+
| `chunkSize` | `number` | 청크 분할 크기 |
|
|
307
|
+
| `chunkSeparator` | `string` | 청크 구분자 |
|
|
308
|
+
| `maxDecodedBytes` | `number` | 최대 디코딩 바이트 |
|
|
309
|
+
| `maxDecompressedBytes` | `number` | 최대 압축해제 바이트 |
|
|
310
|
+
| `onProgress` | `function` | 진행률 콜백 |
|
|
452
311
|
|
|
453
312
|
---
|
|
454
313
|
|
|
455
314
|
## Testing
|
|
456
315
|
|
|
457
|
-
This project uses [Vitest](https://vitest.dev/) for testing.
|
|
458
|
-
|
|
459
316
|
```bash
|
|
460
|
-
#
|
|
461
|
-
pnpm test
|
|
462
|
-
|
|
463
|
-
# Run tests in watch mode
|
|
464
|
-
pnpm test:watch
|
|
317
|
+
pnpm test # 전체 테스트
|
|
318
|
+
pnpm test:watch # 워치 모드
|
|
319
|
+
pnpm test:coverage # 커버리지
|
|
465
320
|
```
|
|
466
321
|
|
|
467
|
-
##
|
|
322
|
+
## Build & Verify
|
|
468
323
|
|
|
469
324
|
```bash
|
|
470
|
-
pnpm lint
|
|
471
325
|
pnpm build
|
|
472
|
-
pnpm
|
|
473
|
-
pnpm pack:check
|
|
326
|
+
pnpm lint
|
|
474
327
|
pnpm bench
|
|
328
|
+
pnpm pack:check
|
|
475
329
|
```
|
|
476
330
|
|
|
477
331
|
---
|
|
478
332
|
|
|
333
|
+
## Credits
|
|
334
|
+
|
|
335
|
+
- Original: [@i3ls](https://github.com/i3l3), [@gunu3371](https://github.com/gunu3371)
|
|
336
|
+
- Repository: [ddunigma](https://github.com/i3l3/ddunigma)
|
|
337
|
+
|
|
479
338
|
## License
|
|
480
339
|
|
|
481
340
|
BSD-2-Clause
|