pure-md5 0.2.0 → 0.2.2
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 +38 -24
- package/dist/adapters/ie11.cjs +1 -2
- package/dist/adapters/ie11.js +1 -2
- package/dist/adapters/node.cjs +1 -2
- package/dist/adapters/node.js +1 -2
- package/dist/adapters/webcrypto.cjs +1 -2
- package/dist/adapters/webcrypto.js +1 -2
- package/dist/index.cjs +1 -2
- package/dist/index.d.ts +149 -5
- package/dist/index.js +3 -2
- package/dist/md5.cjs +1 -0
- package/dist/md5.d.ts +20 -0
- package/dist/md5.js +1 -0
- package/dist/stream/md5-stream.cjs +1 -2
- package/dist/stream/md5-stream.js +1 -2
- package/dist/stream/whatwg-stream.cjs +1 -2
- package/dist/stream/whatwg-stream.js +1 -2
- package/dist/utils/detect.cjs +1 -2
- package/dist/utils/detect.js +3 -2
- package/package.json +10 -15
- package/pure-md5-0.2.1.tgz +0 -0
- package/test-tree-shake.mjs +12 -0
- package/.aliases +0 -19
- package/.bash_profile +0 -12
- package/.bash_prompt +0 -56
- package/.changeset/README.md +0 -32
- package/.changeset/config.json +0 -16
- package/.continue/mcpServers/new-mcp-server.yaml +0 -10
- package/.continue/rules +0 -29
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
- package/.github/ISSUE_TEMPLATE/documentation.md +0 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
- package/.github/workflows/npm-publish.yml +0 -33
- package/.github/workflows/release.yml +0 -42
- package/CHANGELOG.md +0 -9
- package/CONTRIBUTING.md +0 -203
- package/MIGRATION_GUIDE_STREAMS.md +0 -374
- package/STREAM_API.md +0 -582
- package/STREAM_BENCHMARKS.md +0 -232
- package/STREAM_EXAMPLES.md +0 -669
- package/STREAM_OPTIMIZATION_REPORT.md +0 -136
- package/STREAM_TROUBLESHOOTING.md +0 -537
- package/WEB_CRYPTO_TESTS_SUMMARY.md +0 -140
- package/WHATWG_STREAMS.md +0 -191
- package/__tests__/adapters/node-crypto.test.ts +0 -167
- package/__tests__/adapters/web-crypto-node.test.ts +0 -73
- package/__tests__/adapters/web-crypto.test.ts +0 -195
- package/__tests__/add32.test.ts +0 -33
- package/__tests__/fallback.test.ts +0 -345
- package/__tests__/hex.test.ts +0 -38
- package/__tests__/hex_chr.test.ts +0 -20
- package/__tests__/index.test.ts +0 -87
- package/__tests__/integration/fixtures/test-file.txt +0 -1
- package/__tests__/integration/md5-stream-file.test.ts +0 -293
- package/__tests__/integration/node-crypto-file.test.ts +0 -86
- package/__tests__/integration/web-crypto.test.ts +0 -38
- package/__tests__/md51.test.ts +0 -73
- package/__tests__/md5block.test.ts +0 -61
- package/__tests__/md5cycle.test.ts +0 -48
- package/__tests__/round-functions.test.ts +0 -87
- package/__tests__/stream/fs-utils.test.ts +0 -209
- package/__tests__/stream/md5-stream-edge-cases.test.ts +0 -461
- package/__tests__/stream/md5-stream.test.ts +0 -418
- package/__tests__/stream/whatwg-stream.test.ts +0 -355
- package/__tests__/stream/whatwg-stream.test.ts.bak2 +0 -335
- package/benchmarks/md5-stream.bench.ts +0 -212
- package/benchmarks/whatwg-stream.bench.ts +0 -180
- package/dist/adapters/ie11.cjs.map +0 -1
- package/dist/adapters/ie11.js.map +0 -1
- package/dist/adapters/node.cjs.map +0 -1
- package/dist/adapters/node.js.map +0 -1
- package/dist/adapters/webcrypto.cjs.map +0 -1
- package/dist/adapters/webcrypto.js.map +0 -1
- package/dist/chunk-2YXXFGBV.js +0 -2
- package/dist/chunk-2YXXFGBV.js.map +0 -1
- package/dist/chunk-4KSCMS4Q.js +0 -2
- package/dist/chunk-4KSCMS4Q.js.map +0 -1
- package/dist/chunk-6P2QV5SR.js +0 -4
- package/dist/chunk-6P2QV5SR.js.map +0 -1
- package/dist/chunk-G5WHEAIQ.js +0 -2
- package/dist/chunk-G5WHEAIQ.js.map +0 -1
- package/dist/chunk-H2K353LR.js +0 -2
- package/dist/chunk-H2K353LR.js.map +0 -1
- package/dist/chunk-JKVD5LHZ.js +0 -2
- package/dist/chunk-JKVD5LHZ.js.map +0 -1
- package/dist/chunk-NWQ4N5RX.js +0 -2
- package/dist/chunk-NWQ4N5RX.js.map +0 -1
- package/dist/chunk-PHZ7FTYF.js +0 -2
- package/dist/chunk-PHZ7FTYF.js.map +0 -1
- package/dist/chunk-PNZTVQA7.js +0 -2
- package/dist/chunk-PNZTVQA7.js.map +0 -1
- package/dist/chunk-R4JB5MBR.js +0 -2
- package/dist/chunk-R4JB5MBR.js.map +0 -1
- package/dist/chunk-VFOAY6XI.js +0 -2
- package/dist/chunk-VFOAY6XI.js.map +0 -1
- package/dist/chunk-XB5BQIEX.js +0 -2
- package/dist/chunk-XB5BQIEX.js.map +0 -1
- package/dist/core/index.cjs +0 -2
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -19
- package/dist/core/index.d.ts +0 -19
- package/dist/core/index.js +0 -2
- package/dist/core/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -84
- package/dist/index.js.map +0 -1
- package/dist/stream/adapter.cjs +0 -2
- package/dist/stream/adapter.cjs.map +0 -1
- package/dist/stream/adapter.d.cts +0 -63
- package/dist/stream/adapter.d.ts +0 -63
- package/dist/stream/adapter.js +0 -2
- package/dist/stream/adapter.js.map +0 -1
- package/dist/stream/fs-utils.cjs +0 -2
- package/dist/stream/fs-utils.cjs.map +0 -1
- package/dist/stream/fs-utils.d.cts +0 -137
- package/dist/stream/fs-utils.d.ts +0 -137
- package/dist/stream/fs-utils.js +0 -2
- package/dist/stream/fs-utils.js.map +0 -1
- package/dist/stream/index.cjs +0 -2
- package/dist/stream/index.cjs.map +0 -1
- package/dist/stream/index.d.cts +0 -4
- package/dist/stream/index.d.ts +0 -4
- package/dist/stream/index.js +0 -2
- package/dist/stream/index.js.map +0 -1
- package/dist/stream/light/index.cjs +0 -2
- package/dist/stream/light/index.cjs.map +0 -1
- package/dist/stream/light/index.d.cts +0 -4
- package/dist/stream/light/index.d.ts +0 -4
- package/dist/stream/light/index.js +0 -2
- package/dist/stream/light/index.js.map +0 -1
- package/dist/stream/md5-stream.cjs.map +0 -1
- package/dist/stream/md5-stream.js.map +0 -1
- package/dist/stream/whatwg-stream.cjs.map +0 -1
- package/dist/stream/whatwg-stream.js.map +0 -1
- package/dist/types-edGoGJ5V.d.cts +0 -42
- package/dist/types-edGoGJ5V.d.ts +0 -42
- package/dist/utils/detect.cjs.map +0 -1
- package/dist/utils/detect.js.map +0 -1
- package/planning/03-optimization-size-tree-shaking/01-es-modules-tree-shaking.md +0 -152
- package/planning/03-optimization-size-tree-shaking/02-consolidate-modules.md +0 -65
- package/planning/03-optimization-size-tree-shaking/03-remove-duplicate-add32.md +0 -93
- package/planning/03-optimization-size-tree-shaking/04-remove-runtime-check.md +0 -102
- package/planning/03-optimization-size-tree-shaking/05-optimize-loops-performance.md +0 -107
- package/planning/03-optimization-size-tree-shaking/06-tsup-formats-configuration.md +0 -227
- package/planning/03-optimization-size-tree-shaking/07-multiple-build-formats.md +0 -228
- package/planning/03-optimization-size-tree-shaking/08-benchmarks-metrics.md +0 -34
- package/planning/03-optimization-size-tree-shaking/MIGRATION_GUIDE.md +0 -260
- package/planning/03-optimization-size-tree-shaking/README.md +0 -173
- package/planning/03-optimization-size-tree-shaking/SUMMARY.md +0 -168
- package/planning/04-adapter-backend/03-backend-web-crypto.md +0 -149
- package/planning/04-adapter-backend/04-backend-node-crypto.md +0 -181
- package/planning/04-adapter-backend/05-backend-pure-js.md +0 -174
- package/planning/04-adapter-backend/06-backend-ie11.md +0 -158
- package/planning/04-adapter-backend/07-detection-environment.md +0 -232
- package/planning/04-adapter-backend/08-detection-backend.md +0 -210
- package/planning/04-adapter-backend/09-adapter-unified.md +0 -255
- package/planning/04-adapter-backend/10-fallback-mechanism.md +0 -333
- package/planning/04-adapter-backend/11-tests-backend-web-crypto.md +0 -191
- package/planning/04-adapter-backend/12-tests-backend-node-crypto.md +0 -222
- package/planning/04-adapter-backend/README.md +0 -45
- package/planning/05-documentation-publishing/01-README-optimization.md +0 -105
- package/planning/05-documentation-publishing/02-VitePress-site-evaluation.md +0 -136
- package/planning/05-documentation-publishing/03-Changeset-setup.md +0 -192
- package/planning/05-documentation-publishing/04-GitHub-templates.md +0 -252
- package/planning/05-documentation-publishing/README.md +0 -22
- package/planning/05-documentation-publishing/STATUS.md +0 -222
- package/planning/prd.md +0 -405
- package/planning/streams/01-create-md5stream-class.md +0 -69
- package/planning/streams/02-create-factory-api.md +0 -65
- package/planning/streams/03-fs-integration.md +0 -37
- package/planning/streams/04-whatwg-streams-support.md +0 -37
- package/planning/streams/05-audit-optimization.md +0 -121
- package/planning/streams/06-comprehensive-tests-docs.md +0 -137
- package/planning/streams/07-architecture-integration.md +0 -38
- package/planning/streams/README.md +0 -98
- package/tsup.config.ts +0 -24
package/STREAM_EXAMPLES.md
DELETED
|
@@ -1,669 +0,0 @@
|
|
|
1
|
-
# MD5 Streaming API - Usage Examples
|
|
2
|
-
|
|
3
|
-
This document provides practical examples for using the MD5 streaming API in various scenarios.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
1. [Basic Usage](#basic-usage)
|
|
8
|
-
2. [File Operations](#file-operations)
|
|
9
|
-
3. [Browser Usage](#browser-usage)
|
|
10
|
-
4. [Advanced Scenarios](#advanced-scenarios)
|
|
11
|
-
5. [Integration Examples](#integration-examples)
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Basic Usage
|
|
16
|
-
|
|
17
|
-
### Hash a String
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { MD5Stream } from 'pure-md5';
|
|
21
|
-
|
|
22
|
-
const stream = new MD5Stream();
|
|
23
|
-
let digest = '';
|
|
24
|
-
|
|
25
|
-
stream.on('md5', (result) => {
|
|
26
|
-
digest = result.digest;
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
stream.end('Hello, World!');
|
|
30
|
-
console.log(digest); // 65a8e27d8879283831b664bd8b7f0ad4
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Hash a Buffer
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
import { MD5Stream } from 'pure-md5';
|
|
37
|
-
|
|
38
|
-
const data = Buffer.from('Hello, World!', 'utf8');
|
|
39
|
-
const stream = new MD5Stream();
|
|
40
|
-
let digest = '';
|
|
41
|
-
|
|
42
|
-
stream.on('md5', (result) => {
|
|
43
|
-
digest = result.digest;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
stream.end(data);
|
|
47
|
-
console.log(digest); // 65a8e27d8879283831b664bd8b7f0ad4
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Using fromStream (Promise-based)
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
import { fromStream } from 'pure-md5';
|
|
54
|
-
import { Readable } from 'stream';
|
|
55
|
-
|
|
56
|
-
const source = Readable.from(['Hello', ' ', 'World!']);
|
|
57
|
-
const { result } = fromStream(source);
|
|
58
|
-
|
|
59
|
-
result.then(({ digest, bytesProcessed }) => {
|
|
60
|
-
console.log('MD5:', digest);
|
|
61
|
-
console.log('Bytes:', bytesProcessed);
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Using pipeThroughMD5
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
import { pipeThroughMD5 } from 'pure-md5';
|
|
69
|
-
import { Readable } from 'stream';
|
|
70
|
-
|
|
71
|
-
const source = Readable.from(['Hello', ' ', 'World!']);
|
|
72
|
-
const { digest, bytesProcessed } = await pipeThroughMD5(source);
|
|
73
|
-
|
|
74
|
-
console.log('MD5:', digest);
|
|
75
|
-
console.log('Bytes:', bytesProcessed);
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## File Operations
|
|
81
|
-
|
|
82
|
-
### Hash a File
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
import { hashFile } from 'pure-md5';
|
|
86
|
-
|
|
87
|
-
const result = await hashFile('path/to/file.txt');
|
|
88
|
-
console.log('MD5:', result.digest);
|
|
89
|
-
console.log('Bytes:', result.bytesProcessed);
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Hash Multiple Files
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { hashFile } from 'pure-md5';
|
|
96
|
-
|
|
97
|
-
async function hashFiles(files: string[]): Promise<Map<string, string>> {
|
|
98
|
-
const results = new Map<string, string>();
|
|
99
|
-
|
|
100
|
-
for (const file of files) {
|
|
101
|
-
const result = await hashFile(file);
|
|
102
|
-
results.set(file, result.digest);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return results;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const fileHashes = await hashFiles(['file1.txt', 'file2.txt', 'file3.txt']);
|
|
109
|
-
fileHashes.forEach((hash, file) => console.log(`${file}: ${hash}`));
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Hash Files Concurrently
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { hashFile } from 'pure-md5';
|
|
116
|
-
|
|
117
|
-
async function hashFilesConcurrently(files: string[], maxConcurrent = 4): Promise<Map<string, string>> {
|
|
118
|
-
const results = new Map<string, string>();
|
|
119
|
-
const queue = [...files];
|
|
120
|
-
|
|
121
|
-
async function processNext() {
|
|
122
|
-
if (queue.length === 0) return;
|
|
123
|
-
const file = queue.shift();
|
|
124
|
-
const result = await hashFile(file!);
|
|
125
|
-
results.set(file!, result.digest);
|
|
126
|
-
await processNext();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const workers = Array.from({ length: Math.min(maxConcurrent, files.length) }, processNext);
|
|
130
|
-
await Promise.all(workers);
|
|
131
|
-
|
|
132
|
-
return results;
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Hash File with Progress
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
import { MD5Stream } from 'pure-md5';
|
|
140
|
-
import fs from 'fs';
|
|
141
|
-
|
|
142
|
-
async function hashFileWithProgress(filePath: string): Promise<string> {
|
|
143
|
-
return new Promise((resolve, reject) => {
|
|
144
|
-
const fileSize = fs.statSync(filePath).size;
|
|
145
|
-
const stream = new MD5Stream();
|
|
146
|
-
let processed = 0;
|
|
147
|
-
|
|
148
|
-
stream.on('md5', (result) => {
|
|
149
|
-
console.log('\nComplete!');
|
|
150
|
-
console.log('MD5:', result.digest);
|
|
151
|
-
resolve(result.digest);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
stream.on('data', (chunk) => {
|
|
155
|
-
processed += chunk.length;
|
|
156
|
-
const progress = ((processed / fileSize) * 100).toFixed(1);
|
|
157
|
-
process.stdout.write(`\rProgress: ${progress}%`);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
fs.createReadStream(filePath).pipe(stream);
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
await hashFileWithProgress('large-file.bin');
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Verify File Integrity
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
import { verifyFile } from 'pure-md5';
|
|
171
|
-
|
|
172
|
-
async function verifyDownload(filePath: string, expectedHash: string): Promise<void> {
|
|
173
|
-
const isVerified = await verifyFile(filePath, expectedHash);
|
|
174
|
-
|
|
175
|
-
if (isVerified) {
|
|
176
|
-
console.log('✓ File verified successfully!');
|
|
177
|
-
} else {
|
|
178
|
-
console.log('✗ File verification failed!');
|
|
179
|
-
throw new Error('File integrity check failed');
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
await verifyDownload('downloaded-file.zip', '5d41402abc4b2a76b9719d911017c592');
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## Browser Usage
|
|
189
|
-
|
|
190
|
-
### Hash a File Upload
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
import { hashFile } from 'pure-md5';
|
|
194
|
-
|
|
195
|
-
async function handleFileUpload(event: Event): Promise<void> {
|
|
196
|
-
const input = event.target as HTMLInputElement;
|
|
197
|
-
const file = input.files![0];
|
|
198
|
-
|
|
199
|
-
const result = await hashFile(file);
|
|
200
|
-
console.log('File MD5:', result.digest);
|
|
201
|
-
|
|
202
|
-
// Upload with hash...
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
document.querySelector('input[type="file"]').addEventListener('change', handleFileUpload);
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Hash Blob from Canvas
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
import { hashBlob } from 'pure-md5';
|
|
212
|
-
|
|
213
|
-
async function hashCanvas(canvas: HTMLCanvasElement): Promise<string> {
|
|
214
|
-
return new Promise((resolve, reject) => {
|
|
215
|
-
canvas.toBlob(async (blob) => {
|
|
216
|
-
if (!blob) {
|
|
217
|
-
reject(new Error('Failed to create blob'));
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const result = await hashBlob(blob);
|
|
222
|
-
resolve(result.digest);
|
|
223
|
-
}, 'image/png');
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const digest = await hashCanvas(document.querySelector('canvas'));
|
|
228
|
-
console.log('Canvas MD5:', digest);
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Stream File with Progress
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
import { MD5ReadableStream } from 'pure-md5';
|
|
235
|
-
|
|
236
|
-
async function uploadWithHash(file: File, uploadUrl: string): Promise<void> {
|
|
237
|
-
const fileStream = file.stream();
|
|
238
|
-
const md5Stream = new MD5ReadableStream(fileStream);
|
|
239
|
-
|
|
240
|
-
const reader = md5Stream.getReader();
|
|
241
|
-
let bytesProcessed = 0;
|
|
242
|
-
|
|
243
|
-
// Consume stream and track progress
|
|
244
|
-
while (true) {
|
|
245
|
-
const { done, value } = await reader.read();
|
|
246
|
-
if (done) break;
|
|
247
|
-
|
|
248
|
-
bytesProcessed += value.length;
|
|
249
|
-
const progress = (bytesProcessed / file.size * 100).toFixed(1);
|
|
250
|
-
console.log(`Upload progress: ${progress}%`);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const result = await md5Stream.getResult();
|
|
254
|
-
console.log('Upload complete. MD5:', result.digest);
|
|
255
|
-
|
|
256
|
-
// Now upload with hash metadata
|
|
257
|
-
// await fetch(uploadUrl, { method: 'POST', body: file, headers: { 'X-MD5': result.digest } });
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
## Advanced Scenarios
|
|
264
|
-
|
|
265
|
-
### Custom add32 Function
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
import { MD5Stream } from 'pure-md5';
|
|
269
|
-
|
|
270
|
-
// For testing - use a known add32 implementation
|
|
271
|
-
const customAdd32 = (x: number, y: number): number => {
|
|
272
|
-
// Custom implementation for compatibility testing
|
|
273
|
-
const result = x + y;
|
|
274
|
-
return (result & 0xffffffff) >>> 0;
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
const stream = new MD5Stream({ add32: customAdd32 });
|
|
278
|
-
let digest = '';
|
|
279
|
-
|
|
280
|
-
stream.on('md5', (result) => {
|
|
281
|
-
digest = result.digest;
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
stream.end('test with custom add32');
|
|
285
|
-
console.log(digest);
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Stream with Timeout
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
import { MD5Stream } from 'pure-md5';
|
|
292
|
-
|
|
293
|
-
async function hashWithTimeout(source: NodeJS.ReadableStream, timeoutMs: number): Promise<string> {
|
|
294
|
-
return new Promise((resolve, reject) => {
|
|
295
|
-
const timeout = setTimeout(() => {
|
|
296
|
-
reject(new Error('Hashing timeout'));
|
|
297
|
-
}, timeoutMs);
|
|
298
|
-
|
|
299
|
-
const stream = new MD5Stream();
|
|
300
|
-
|
|
301
|
-
stream.on('md5', (result) => {
|
|
302
|
-
clearTimeout(timeout);
|
|
303
|
-
resolve(result.digest);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
stream.on('error', (error) => {
|
|
307
|
-
clearTimeout(timeout);
|
|
308
|
-
reject(error);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
source.pipe(stream);
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
const digest = await hashWithTimeout(fs.createReadStream('file.txt'), 5000);
|
|
317
|
-
console.log('MD5:', digest);
|
|
318
|
-
} catch (error) {
|
|
319
|
-
console.error('Error:', error.message);
|
|
320
|
-
}
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Multiple Hashes in Parallel
|
|
324
|
-
|
|
325
|
-
```typescript
|
|
326
|
-
import { hashFile } from 'pure-md5';
|
|
327
|
-
|
|
328
|
-
interface HashResult {
|
|
329
|
-
file: string;
|
|
330
|
-
digest: string;
|
|
331
|
-
size: number;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
async function hashFilesParallel(files: string[]): Promise<HashResult[]> {
|
|
335
|
-
const promises = files.map(async (file) => {
|
|
336
|
-
const result = await hashFile(file);
|
|
337
|
-
const size = (await fs.promises.stat(file)).size;
|
|
338
|
-
return { file, digest: result.digest, size };
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
return Promise.all(promises);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const results = await hashFilesParallel(['file1.txt', 'file2.txt', 'file3.txt']);
|
|
345
|
-
results.forEach(r => console.log(`${r.file}: ${r.digest} (${r.size} bytes)`));
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### Detect File Changes
|
|
349
|
-
|
|
350
|
-
```typescript
|
|
351
|
-
import { hashFile } from 'pure-md5';
|
|
352
|
-
|
|
353
|
-
interface FileHash {
|
|
354
|
-
path: string;
|
|
355
|
-
hash: string;
|
|
356
|
-
timestamp: number;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async function detectChanges(previous: Map<string, FileHash>, currentFiles: string[]): Promise<void> {
|
|
360
|
-
const changes: string[] = [];
|
|
361
|
-
|
|
362
|
-
// Check existing files
|
|
363
|
-
for (const file of currentFiles) {
|
|
364
|
-
const currentHash = await hashFile(file);
|
|
365
|
-
const previousHash = previous.get(file);
|
|
366
|
-
|
|
367
|
-
if (!previousHash || previousHash.hash !== currentHash.digest) {
|
|
368
|
-
changes.push(file);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Check for deleted files
|
|
373
|
-
for (const [file] of previous) {
|
|
374
|
-
if (!currentFiles.includes(file)) {
|
|
375
|
-
changes.push(file);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (changes.length > 0) {
|
|
380
|
-
console.log('Changed files:', changes);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
## Integration Examples
|
|
388
|
-
|
|
389
|
-
### Express.js Middleware
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
import { hashFile } from 'pure-md5';
|
|
393
|
-
import express, { Request, Response, NextFunction } from 'express';
|
|
394
|
-
|
|
395
|
-
interface RequestWithHash extends Request {
|
|
396
|
-
fileHash?: string;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const app = express();
|
|
400
|
-
|
|
401
|
-
// Middleware to compute file hash
|
|
402
|
-
app.use((req: RequestWithHash, res: Response, next: NextFunction) => {
|
|
403
|
-
if (req.body && req.body.file) {
|
|
404
|
-
hashFile(req.body.file.path)
|
|
405
|
-
.then(result => {
|
|
406
|
-
req.fileHash = result.digest;
|
|
407
|
-
next();
|
|
408
|
-
})
|
|
409
|
-
.catch(next);
|
|
410
|
-
} else {
|
|
411
|
-
next();
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
app.post('/upload', (req: RequestWithHash, res: Response) => {
|
|
416
|
-
res.json({
|
|
417
|
-
hash: req.fileHash,
|
|
418
|
-
message: 'File uploaded'
|
|
419
|
-
});
|
|
420
|
-
});
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### AWS Lambda Function
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
import { hashFile } from 'pure-md5';
|
|
427
|
-
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
428
|
-
|
|
429
|
-
const s3 = new S3Client({});
|
|
430
|
-
|
|
431
|
-
export async function handler(event: any): Promise<any> {
|
|
432
|
-
const bucket = event.bucket;
|
|
433
|
-
const key = event.key;
|
|
434
|
-
|
|
435
|
-
// Get object from S3
|
|
436
|
-
const command = new GetObjectCommand({ Bucket: bucket, Key: key });
|
|
437
|
-
const response = await s3.send(command);
|
|
438
|
-
|
|
439
|
-
// Hash the content
|
|
440
|
-
const content = await response.Body!.transformToString();
|
|
441
|
-
const hash = await hashFile(content);
|
|
442
|
-
|
|
443
|
-
return {
|
|
444
|
-
statusCode: 200,
|
|
445
|
-
body: JSON.stringify({
|
|
446
|
-
md5: hash.digest,
|
|
447
|
-
size: hash.bytesProcessed
|
|
448
|
-
})
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### GraphQL Resolver
|
|
454
|
-
|
|
455
|
-
```typescript
|
|
456
|
-
import { hashFile } from 'pure-md5';
|
|
457
|
-
|
|
458
|
-
const resolvers = {
|
|
459
|
-
Query: {
|
|
460
|
-
fileHash: async (_, { path }: { path: string }) => {
|
|
461
|
-
const result = await hashFile(path);
|
|
462
|
-
return {
|
|
463
|
-
digest: result.digest,
|
|
464
|
-
bytesProcessed: result.bytesProcessed,
|
|
465
|
-
path
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### CLI Tool
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
#!/usr/bin/env node
|
|
476
|
-
import { hashFile } from 'pure-md5';
|
|
477
|
-
import fs from 'fs';
|
|
478
|
-
|
|
479
|
-
async function main() {
|
|
480
|
-
const filePath = process.argv[2];
|
|
481
|
-
|
|
482
|
-
if (!filePath) {
|
|
483
|
-
console.error('Usage: md5-hash <file>');
|
|
484
|
-
process.exit(1);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
try {
|
|
488
|
-
const result = await hashFile(filePath);
|
|
489
|
-
console.log(result.digest);
|
|
490
|
-
} catch (error) {
|
|
491
|
-
console.error('Error:', error.message);
|
|
492
|
-
process.exit(1);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
main();
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
### React Component
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
import { useState, useEffect } from 'react';
|
|
503
|
-
import { hashFile } from 'pure-md5';
|
|
504
|
-
|
|
505
|
-
function FileHasher() {
|
|
506
|
-
const [file, setFile] = useState<File | null>(null);
|
|
507
|
-
const [hash, setHash] = useState<string>('');
|
|
508
|
-
const [loading, setLoading] = useState(false);
|
|
509
|
-
|
|
510
|
-
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
511
|
-
if (event.target.files && event.target.files[0]) {
|
|
512
|
-
setFile(event.target.files[0]);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
useEffect(() => {
|
|
517
|
-
if (file) {
|
|
518
|
-
setLoading(true);
|
|
519
|
-
hashFile(file)
|
|
520
|
-
.then(result => {
|
|
521
|
-
setHash(result.digest);
|
|
522
|
-
setLoading(false);
|
|
523
|
-
})
|
|
524
|
-
.catch(error => {
|
|
525
|
-
console.error(error);
|
|
526
|
-
setLoading(false);
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
}, [file]);
|
|
530
|
-
|
|
531
|
-
return (
|
|
532
|
-
<div>
|
|
533
|
-
<input type="file" onChange={handleFileChange} />
|
|
534
|
-
{loading && <p>Computing hash...</p>}
|
|
535
|
-
{hash && <p>MD5: {hash}</p>}
|
|
536
|
-
</div>
|
|
537
|
-
);
|
|
538
|
-
}
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
### Node.js CLI Tool with Progress
|
|
542
|
-
|
|
543
|
-
```typescript
|
|
544
|
-
#!/usr/bin/env node
|
|
545
|
-
import { MD5Stream } from 'pure-md5';
|
|
546
|
-
import fs from 'fs';
|
|
547
|
-
import readline from 'readline';
|
|
548
|
-
|
|
549
|
-
const rl = readline.createInterface({
|
|
550
|
-
input: process.stdin,
|
|
551
|
-
output: process.stdout
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
const filePath = process.argv[2];
|
|
555
|
-
|
|
556
|
-
if (!filePath) {
|
|
557
|
-
console.error('Usage: md5-hash <file>');
|
|
558
|
-
process.exit(1);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
const fileSize = fs.statSync(filePath).size;
|
|
562
|
-
const stream = new MD5Stream();
|
|
563
|
-
let processed = 0;
|
|
564
|
-
|
|
565
|
-
const updateProgress = () => {
|
|
566
|
-
const progress = ((processed / fileSize) * 100).toFixed(1);
|
|
567
|
-
process.stdout.write(`\r${progress}% [${'#'.padEnd(50, ' ').substring(0, Math.floor(progress / 2))}]`);
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
stream.on('data', (chunk) => {
|
|
571
|
-
processed += chunk.length;
|
|
572
|
-
if (processed % (64 * 1024) === 0) { // Update every 64KB
|
|
573
|
-
updateProgress();
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
stream.on('md5', (result) => {
|
|
578
|
-
updateProgress();
|
|
579
|
-
console.log(`\n${result.digest} ${filePath}`);
|
|
580
|
-
rl.close();
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
stream.on('error', (error) => {
|
|
584
|
-
console.error(`Error: ${error.message}`);
|
|
585
|
-
rl.close();
|
|
586
|
-
process.exit(1);
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
fs.createReadStream(filePath).pipe(stream);
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
---
|
|
593
|
-
|
|
594
|
-
## Performance Examples
|
|
595
|
-
|
|
596
|
-
### Optimal File Hashing
|
|
597
|
-
|
|
598
|
-
```typescript
|
|
599
|
-
import { MD5Stream } from 'pure-md5';
|
|
600
|
-
import fs from 'fs';
|
|
601
|
-
|
|
602
|
-
async function optimalHashFile(filePath: string): Promise<string> {
|
|
603
|
-
return new Promise((resolve, reject) => {
|
|
604
|
-
const stream = new MD5Stream();
|
|
605
|
-
|
|
606
|
-
stream.on('md5', (result) => {
|
|
607
|
-
resolve(result.digest);
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
stream.on('error', reject);
|
|
611
|
-
|
|
612
|
-
// Use piping for optimal performance
|
|
613
|
-
fs.createReadStream(filePath).pipe(stream);
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
### Memory-Efficient Large File Processing
|
|
619
|
-
|
|
620
|
-
```typescript
|
|
621
|
-
import { MD5Stream } from 'pure-md5';
|
|
622
|
-
|
|
623
|
-
async function hashLargeFileEfficiently(source: NodeJS.ReadableStream): Promise<string> {
|
|
624
|
-
return new Promise((resolve, reject) => {
|
|
625
|
-
const stream = new MD5Stream();
|
|
626
|
-
|
|
627
|
-
stream.on('md5', (result) => {
|
|
628
|
-
resolve(result.digest);
|
|
629
|
-
});
|
|
630
|
-
|
|
631
|
-
stream.on('error', reject);
|
|
632
|
-
|
|
633
|
-
// Set optimal buffer size
|
|
634
|
-
source.setEncoding('binary');
|
|
635
|
-
source.pipe(stream);
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
### Batch Processing
|
|
641
|
-
|
|
642
|
-
```typescript
|
|
643
|
-
import { hashFile } from 'pure-md5';
|
|
644
|
-
|
|
645
|
-
async function batchHashFiles(
|
|
646
|
-
files: string[],
|
|
647
|
-
batchSize: number = 10
|
|
648
|
-
): Promise<Map<string, string>> {
|
|
649
|
-
const results = new Map<string, string>();
|
|
650
|
-
|
|
651
|
-
for (let i = 0; i < files.length; i += batchSize) {
|
|
652
|
-
const batch = files.slice(i, i + batchSize);
|
|
653
|
-
const batchResults = await Promise.all(batch.map(f => hashFile(f)));
|
|
654
|
-
|
|
655
|
-
batch.forEach((file, index) => {
|
|
656
|
-
results.set(file, batchResults[index].digest);
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
return results;
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
## See Also
|
|
665
|
-
|
|
666
|
-
- [STREAM_API.md](STREAM_API.md) - Complete API documentation
|
|
667
|
-
- [MIGRATION_GUIDE_STREAMS.md](MIGRATION_GUIDE_STREAMS.md) - Migration examples
|
|
668
|
-
- [STREAM_TROUBLESHOOTING.md](STREAM_TROUBLESHOOTING.md) - Common issues
|
|
669
|
-
- [STREAM_BENCHMARKS.md](STREAM_BENCHMARKS.md) - Performance benchmarks
|