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