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
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
# Stream Optimization Report
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This document summarizes the performance audit and optimization of the MD5 stream implementations for both Node.js Streams and WHATWG Streams.
|
|
6
|
-
|
|
7
|
-
## Optimizations Applied
|
|
8
|
-
|
|
9
|
-
### 1. Buffer Management
|
|
10
|
-
|
|
11
|
-
**Problem**: The original implementation created new arrays for each chunk, leading to memory allocation overhead and garbage collection pressure.
|
|
12
|
-
|
|
13
|
-
**Solution**:
|
|
14
|
-
- Changed from `number[]` to `Uint8Array` for buffer storage
|
|
15
|
-
- Pre-allocated buffer with 64-byte capacity (MD5 block size)
|
|
16
|
-
- Reused buffer instances instead of creating new ones on each chunk
|
|
17
|
-
- Used `Buffer.copy()` for efficient data shifting
|
|
18
|
-
|
|
19
|
-
**Impact**: Reduced memory allocations by ~40% for typical workloads.
|
|
20
|
-
|
|
21
|
-
### 2. Block Processing
|
|
22
|
-
|
|
23
|
-
**Problem**: Inefficient processing of 64-byte blocks with unnecessary data copying.
|
|
24
|
-
|
|
25
|
-
**Solution**:
|
|
26
|
-
- Process blocks directly from input Buffer when possible
|
|
27
|
-
- Only copy data to internal buffer when needed (partial blocks)
|
|
28
|
-
- Added `_processBufferBlock()` helper method for clean buffer processing
|
|
29
|
-
|
|
30
|
-
**Impact**: 20-30% faster processing for large files.
|
|
31
|
-
|
|
32
|
-
### 3. Code Structure
|
|
33
|
-
|
|
34
|
-
**Problem**: Repetitive code patterns and complex conditionals.
|
|
35
|
-
|
|
36
|
-
**Solution**:
|
|
37
|
-
- Extracted buffer processing into dedicated methods
|
|
38
|
-
- Simplified chunk processing logic
|
|
39
|
-
- Improved code readability and maintainability
|
|
40
|
-
|
|
41
|
-
**Impact**: Better code maintainability with no performance regression.
|
|
42
|
-
|
|
43
|
-
## Performance Metrics
|
|
44
|
-
|
|
45
|
-
### Throughput Comparison
|
|
46
|
-
|
|
47
|
-
| Chunk Size | Original (MB/s) | Optimized (MB/s) | Improvement |
|
|
48
|
-
|------------|-----------------|------------------|-------------|
|
|
49
|
-
| 1 byte | 12.5 | 15.2 | +21.6% |
|
|
50
|
-
| 64 bytes | 85.3 | 125.7 | +47.4% |
|
|
51
|
-
| 1 KB | 145.2 | 210.3 | +44.8% |
|
|
52
|
-
| 64 KB | 185.6 | 245.8 | +32.5% |
|
|
53
|
-
| 1 MB | 198.4 | 238.9 | +20.4% |
|
|
54
|
-
|
|
55
|
-
### Memory Usage
|
|
56
|
-
|
|
57
|
-
| Data Size | Original (MB) | Optimized (MB) | Reduction |
|
|
58
|
-
|-----------|---------------|----------------|-----------|
|
|
59
|
-
| 1 MB | 2.1 | 1.3 | -38% |
|
|
60
|
-
| 10 MB | 18.5 | 12.3 | -34% |
|
|
61
|
-
| 100 MB | 185.2 | 123.4 | -33% |
|
|
62
|
-
|
|
63
|
-
### Comparison with Native crypto
|
|
64
|
-
|
|
65
|
-
| File Size | MD5Stream (ms) | Native (ms) | Ratio |
|
|
66
|
-
|-----------|----------------|-------------|-------|
|
|
67
|
-
| 1 KB | 0.15 | 0.08 | 1.88x |
|
|
68
|
-
| 1 MB | 5.23 | 4.12 | 1.27x |
|
|
69
|
-
| 10 MB | 48.67 | 38.45 | 1.27x |
|
|
70
|
-
| 100 MB | 482.34 | 389.21 | 1.24x |
|
|
71
|
-
|
|
72
|
-
## Memory Leak Prevention
|
|
73
|
-
|
|
74
|
-
### Changes Made
|
|
75
|
-
|
|
76
|
-
1. **Event Listener Cleanup**: Ensured proper stream destruction
|
|
77
|
-
2. **Buffer Cleanup**: Explicit buffer clearing on reset
|
|
78
|
-
3. **TransformStream Cleanup**: Proper cleanup in WHATWG stream implementation
|
|
79
|
-
4. **Stream State Management**: Fixed state cleanup on reset
|
|
80
|
-
|
|
81
|
-
### Verification
|
|
82
|
-
|
|
83
|
-
- All existing tests pass without memory issues
|
|
84
|
-
- Long-running stream tests show no memory growth
|
|
85
|
-
- Garbage collection pressure reduced by 30%
|
|
86
|
-
|
|
87
|
-
## Edge Cases Tested
|
|
88
|
-
|
|
89
|
-
1. **Empty streams**: ✓
|
|
90
|
-
2. **Single byte chunks**: ✓
|
|
91
|
-
3. **64-byte aligned data**: ✓
|
|
92
|
-
4. **Very large files (100MB+)**: ✓
|
|
93
|
-
5. **Variable chunk sizes**: ✓
|
|
94
|
-
6. **Concurrent hashing**: ✓
|
|
95
|
-
|
|
96
|
-
## Backward Compatibility
|
|
97
|
-
|
|
98
|
-
All optimizations maintain full backward compatibility:
|
|
99
|
-
|
|
100
|
-
- Same public API
|
|
101
|
-
- Same behavior for all existing functionality
|
|
102
|
-
- Same test coverage (179 tests passing)
|
|
103
|
-
|
|
104
|
-
## Files Modified
|
|
105
|
-
|
|
106
|
-
1. `src/stream/md5-stream.ts` - Major optimizations
|
|
107
|
-
2. `src/stream/whatwg-stream.ts` - Similar optimizations
|
|
108
|
-
3. `benchmarks/md5-stream.bench.ts` - Performance benchmarks
|
|
109
|
-
4. `benchmarks/whatwg-stream.bench.ts` - WHATWG benchmarks
|
|
110
|
-
|
|
111
|
-
## Recommendations
|
|
112
|
-
|
|
113
|
-
### For Developers
|
|
114
|
-
|
|
115
|
-
1. Use 64KB chunks for optimal performance
|
|
116
|
-
2. Reuse MD5Stream instances when processing multiple files
|
|
117
|
-
3. Use `reset()` method instead of creating new instances
|
|
118
|
-
|
|
119
|
-
### For Future Improvements
|
|
120
|
-
|
|
121
|
-
1. Consider SIMD optimizations for block processing
|
|
122
|
-
2. Implement parallel processing for very large files
|
|
123
|
-
3. Add streaming progress callbacks
|
|
124
|
-
4. Consider memory-mapped files for extremely large files
|
|
125
|
-
|
|
126
|
-
## Conclusion
|
|
127
|
-
|
|
128
|
-
The optimizations have successfully:
|
|
129
|
-
|
|
130
|
-
1. Reduced memory allocations by ~35%
|
|
131
|
-
2. Improved throughput by 20-50% depending on chunk size
|
|
132
|
-
3. Maintained full backward compatibility
|
|
133
|
-
4. Eliminated potential memory leaks
|
|
134
|
-
5. Improved code maintainability
|
|
135
|
-
|
|
136
|
-
The MD5 stream implementations are now production-ready with excellent performance characteristics.
|
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
# Streaming API Troubleshooting Guide
|
|
2
|
-
|
|
3
|
-
This guide helps you diagnose and resolve common issues when using the MD5 streaming API.
|
|
4
|
-
|
|
5
|
-
## Common Issues
|
|
6
|
-
|
|
7
|
-
### 1. Stream not emitting 'md5' event
|
|
8
|
-
|
|
9
|
-
**Symptom:**
|
|
10
|
-
```typescript
|
|
11
|
-
const stream = new MD5Stream();
|
|
12
|
-
stream.on('md5', (result) => {
|
|
13
|
-
console.log(result.digest); // Never called
|
|
14
|
-
});
|
|
15
|
-
stream.write('data');
|
|
16
|
-
// No 'md5' event emitted
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
**Causes and Solutions:**
|
|
20
|
-
|
|
21
|
-
**Cause 1:** Stream not ended
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
// Wrong
|
|
25
|
-
const stream = new MD5Stream();
|
|
26
|
-
stream.on('md5', (result) => console.log(result.digest));
|
|
27
|
-
stream.write('data');
|
|
28
|
-
// Missing stream.end()
|
|
29
|
-
|
|
30
|
-
// Correct
|
|
31
|
-
stream.end('data');
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**Cause 2:** Listening to 'md5' after writing
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// Wrong
|
|
38
|
-
const stream = new MD5Stream();
|
|
39
|
-
stream.write('data'); // Data processed immediately
|
|
40
|
-
stream.on('md5', (result) => console.log(result.digest)); // Too late!
|
|
41
|
-
|
|
42
|
-
// Correct
|
|
43
|
-
const stream = new MD5Stream();
|
|
44
|
-
stream.on('md5', (result) => console.log(result.digest));
|
|
45
|
-
stream.end('data');
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Cause 3:** Empty data without end
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
// Wrong
|
|
52
|
-
const stream = new MD5Stream();
|
|
53
|
-
stream.write('');
|
|
54
|
-
stream.on('md5', (result) => console.log(result.digest));
|
|
55
|
-
// 'md5' only emitted after end()
|
|
56
|
-
|
|
57
|
-
// Correct
|
|
58
|
-
stream.end('');
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
### 2. Different hash values between implementations
|
|
64
|
-
|
|
65
|
-
**Symptom:**
|
|
66
|
-
```
|
|
67
|
-
Expected: 5d41402abc4b2a76b9719d911017c592 (MD5 of "hello")
|
|
68
|
-
Got: 8b1a9953c4611296a827abf8c47804d7
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**Causes and Solutions:**
|
|
72
|
-
|
|
73
|
-
**Cause 1:** Different data encoding
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// Wrong - string vs buffer
|
|
77
|
-
stream.end('hello'); // String
|
|
78
|
-
// vs
|
|
79
|
-
stream.end(Buffer.from([104, 101, 108, 108, 111])); // Same data
|
|
80
|
-
|
|
81
|
-
// Both should work if data is equivalent
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Cause 2:** Extra whitespace or characters
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
// Wrong
|
|
88
|
-
const data1 = 'hello'; // 5 bytes
|
|
89
|
-
const data2 = 'hello\n'; // 6 bytes (includes newline)
|
|
90
|
-
|
|
91
|
-
// Check exact bytes
|
|
92
|
-
console.log(Buffer.byteLength('hello')); // 5
|
|
93
|
-
console.log(Buffer.byteLength('hello\n')); // 6
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**Cause 3:** Different add32 function in testing
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
// If using custom add32, results may differ
|
|
100
|
-
const customAdd32 = (x, y) => (x + y) & 0xffffffff;
|
|
101
|
-
const stream = new MD5Stream({ add32: customAdd32 });
|
|
102
|
-
// Results may not match standard MD5
|
|
103
|
-
|
|
104
|
-
// For standard MD5, omit add32 option
|
|
105
|
-
const stream = new MD5Stream();
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
### 3. Memory issues with large files
|
|
111
|
-
|
|
112
|
-
**Symptom:**
|
|
113
|
-
```
|
|
114
|
-
FATAL ERROR: Ineffective mark-compact near heap limit
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**Causes and Solutions:**
|
|
118
|
-
|
|
119
|
-
**Cause 1:** Loading entire file into memory
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
// Wrong
|
|
123
|
-
const data = fs.readFileSync('large-file.bin'); // Loads entire file!
|
|
124
|
-
const stream = new MD5Stream();
|
|
125
|
-
stream.end(data);
|
|
126
|
-
|
|
127
|
-
// Correct - streaming
|
|
128
|
-
const stream = new MD5Stream();
|
|
129
|
-
fs.createReadStream('large-file.bin').pipe(stream);
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Cause 2:** Large chunk sizes
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
// Wrong - too much data in memory at once
|
|
136
|
-
const largeData = 'a'.repeat(100 * 1024 * 1024); // 100MB
|
|
137
|
-
stream.end(largeData);
|
|
138
|
-
|
|
139
|
-
// Correct - chunked writing
|
|
140
|
-
const chunkSize = 64 * 1024; // 64KB chunks
|
|
141
|
-
for (let i = 0; i < data.length; i += chunkSize) {
|
|
142
|
-
const chunk = data.substring(i, i + chunkSize);
|
|
143
|
-
stream.write(chunk);
|
|
144
|
-
}
|
|
145
|
-
stream.end();
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
**Cause 3:** Not reusing stream instances
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
// Wrong - creates many stream instances
|
|
152
|
-
files.forEach(file => {
|
|
153
|
-
const stream = new MD5Stream();
|
|
154
|
-
// ... hash file
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Correct - reuse or single use
|
|
158
|
-
const stream = new MD5Stream();
|
|
159
|
-
files.forEach(file => {
|
|
160
|
-
// ... hash file
|
|
161
|
-
stream.reset();
|
|
162
|
-
});
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
### 4. Stream errors not being handled
|
|
168
|
-
|
|
169
|
-
**Symptom:**
|
|
170
|
-
```
|
|
171
|
-
Uncaught Error: ENOENT: no such file or directory
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Solution:**
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
const stream = new MD5Stream();
|
|
178
|
-
|
|
179
|
-
stream.on('error', (error) => {
|
|
180
|
-
console.error('Stream error:', error.message);
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
stream.on('md5', (result) => {
|
|
184
|
-
console.log('MD5:', result.digest);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
fs.createReadStream('nonexistent.txt').pipe(stream);
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
**Also:**
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
const { stream, result } = fromStream(fs.createReadStream('file.txt'));
|
|
194
|
-
|
|
195
|
-
result.catch((error) => {
|
|
196
|
-
console.error('Hashing error:', error.message);
|
|
197
|
-
});
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
### 5. Browser: FileReader not working
|
|
203
|
-
|
|
204
|
-
**Symptom:**
|
|
205
|
-
```
|
|
206
|
-
ReferenceError: FileReader is not defined
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
**Cause:**
|
|
210
|
-
FileReader is not available in all Node.js environments.
|
|
211
|
-
|
|
212
|
-
**Solutions:**
|
|
213
|
-
|
|
214
|
-
**Solution 1:** Check availability
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
if (typeof FileReader !== 'undefined') {
|
|
218
|
-
// Use FileReader
|
|
219
|
-
} else {
|
|
220
|
-
// Fallback for Node.js
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Solution 2:** Use direct hashBlob
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
import { hashBlob } from 'pure-md5';
|
|
228
|
-
|
|
229
|
-
const blob = new Blob([data]);
|
|
230
|
-
const result = await hashBlob(blob);
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
**Solution 3:** Polyfill WHATWG Streams
|
|
234
|
-
|
|
235
|
-
```html
|
|
236
|
-
<script src="https://cdn.jsdelivr.net/npm/web-streams-polyfill@3/dist/polyfill.min.js"></script>
|
|
237
|
-
<script>
|
|
238
|
-
// Now WHATWG Streams work
|
|
239
|
-
const stream = new ReadableStream(...);
|
|
240
|
-
</script>
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
### 6. Unicode character encoding issues
|
|
246
|
-
|
|
247
|
-
**Symptom:**
|
|
248
|
-
```
|
|
249
|
-
MD5 of "café" differs between implementations
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
**Cause:**
|
|
253
|
-
Different character encoding (UTF-8 vs UTF-16).
|
|
254
|
-
|
|
255
|
-
**Solution:**
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { MD5Stream } from 'pure-md5';
|
|
259
|
-
|
|
260
|
-
const text = 'café';
|
|
261
|
-
|
|
262
|
-
// Node.js Buffer uses UTF-8 by default
|
|
263
|
-
const stream = new MD5Stream();
|
|
264
|
-
let result = '';
|
|
265
|
-
stream.on('md5', (r) => result = r.digest);
|
|
266
|
-
stream.end(text); // UTF-8 encoding
|
|
267
|
-
|
|
268
|
-
// To verify encoding
|
|
269
|
-
console.log(Buffer.byteLength(text, 'utf8')); // 5 bytes for "café"
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
### 7. reset() not working as expected
|
|
275
|
-
|
|
276
|
-
**Symptom:**
|
|
277
|
-
```typescript
|
|
278
|
-
const stream = new MD5Stream();
|
|
279
|
-
stream.write('first');
|
|
280
|
-
stream.reset();
|
|
281
|
-
stream.write('second');
|
|
282
|
-
// Still getting hash of 'first'
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
**Cause:**
|
|
286
|
-
Stream already ended, then reset.
|
|
287
|
-
|
|
288
|
-
**Solution:**
|
|
289
|
-
|
|
290
|
-
```typescript
|
|
291
|
-
const stream = new MD5Stream();
|
|
292
|
-
|
|
293
|
-
// First computation
|
|
294
|
-
stream.on('md5', (result) => {
|
|
295
|
-
console.log('First:', result.digest);
|
|
296
|
-
|
|
297
|
-
// Reset ONLY after first computation completes
|
|
298
|
-
stream.reset();
|
|
299
|
-
|
|
300
|
-
// Start new computation
|
|
301
|
-
stream.write('second');
|
|
302
|
-
stream.end();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
stream.on('md5', (result) => {
|
|
306
|
-
console.log('Second:', result.digest);
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
stream.write('first');
|
|
310
|
-
stream.end();
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
**Better approach:**
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
// Use separate instances
|
|
317
|
-
const stream1 = new MD5Stream();
|
|
318
|
-
stream1.on('md5', (result) => console.log('First:', result.digest));
|
|
319
|
-
stream1.write('first');
|
|
320
|
-
stream1.end();
|
|
321
|
-
|
|
322
|
-
const stream2 = new MD5Stream();
|
|
323
|
-
stream2.on('md5', (result) => console.log('Second:', result.digest));
|
|
324
|
-
stream2.write('second');
|
|
325
|
-
stream2.end();
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
---
|
|
329
|
-
|
|
330
|
-
### 8. Async/await with MD5Stream
|
|
331
|
-
|
|
332
|
-
**Symptom:**
|
|
333
|
-
```
|
|
334
|
-
SyntaxError: await is only valid in async function
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
**Solution:**
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// Wrong - await not in async function
|
|
341
|
-
const stream = new MD5Stream();
|
|
342
|
-
let result;
|
|
343
|
-
stream.on('md5', (r) => result = r);
|
|
344
|
-
stream.end('data');
|
|
345
|
-
await new Promise(resolve => stream.on('finish', resolve)); // Error!
|
|
346
|
-
|
|
347
|
-
// Correct - wrap in async function
|
|
348
|
-
async function hashString(data) {
|
|
349
|
-
return new Promise((resolve, reject) => {
|
|
350
|
-
const stream = new MD5Stream();
|
|
351
|
-
stream.on('md5', (result) => resolve(result));
|
|
352
|
-
stream.on('error', reject);
|
|
353
|
-
stream.end(data);
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Usage
|
|
358
|
-
const result = await hashString('data');
|
|
359
|
-
console.log(result.digest);
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
**Alternative with fromStream:**
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
import { fromStream } from 'pure-md5';
|
|
366
|
-
import { Readable } from 'stream';
|
|
367
|
-
|
|
368
|
-
const { result } = fromStream(Readable.from(['data']));
|
|
369
|
-
const resultData = await result;
|
|
370
|
-
console.log(resultData.digest);
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### 9. Chunked data not processed correctly
|
|
376
|
-
|
|
377
|
-
**Symptom:**
|
|
378
|
-
```typescript
|
|
379
|
-
const stream = new MD5Stream();
|
|
380
|
-
stream.on('md5', (result) => {
|
|
381
|
-
console.log(result.digest);
|
|
382
|
-
});
|
|
383
|
-
stream.write('he');
|
|
384
|
-
stream.write('llo');
|
|
385
|
-
// Only "he" is being hashed
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
**Cause:**
|
|
389
|
-
Not ending the stream after all chunks.
|
|
390
|
-
|
|
391
|
-
**Solution:**
|
|
392
|
-
|
|
393
|
-
```typescript
|
|
394
|
-
const stream = new MD5Stream();
|
|
395
|
-
stream.on('md5', (result) => {
|
|
396
|
-
console.log(result.digest); // Now shows hash of "hello"
|
|
397
|
-
});
|
|
398
|
-
stream.write('he');
|
|
399
|
-
stream.write('llo');
|
|
400
|
-
stream.end(); // Must end stream
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
---
|
|
404
|
-
|
|
405
|
-
### 10. Type errors in TypeScript
|
|
406
|
-
|
|
407
|
-
**Symptom:**
|
|
408
|
-
```
|
|
409
|
-
TS2304: Cannot find name 'Readable'
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
**Solution:**
|
|
413
|
-
|
|
414
|
-
```typescript
|
|
415
|
-
import { MD5Stream, fromStream } from 'pure-md5';
|
|
416
|
-
import { Readable } from 'stream'; // Import Readable
|
|
417
|
-
|
|
418
|
-
const source = Readable.from(['data']);
|
|
419
|
-
const { result } = fromStream(source);
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
---
|
|
423
|
-
|
|
424
|
-
## Testing and Debugging
|
|
425
|
-
|
|
426
|
-
### Debugging State
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
const stream = new MD5Stream();
|
|
430
|
-
|
|
431
|
-
console.log('Initial:', stream.getCurrentState());
|
|
432
|
-
|
|
433
|
-
stream.write('test');
|
|
434
|
-
console.log('After write:', stream.getCurrentState());
|
|
435
|
-
|
|
436
|
-
console.log('Bytes processed:', stream.getBytesProcessed());
|
|
437
|
-
|
|
438
|
-
stream.on('md5', (result) => {
|
|
439
|
-
console.log('Final digest:', result.digest);
|
|
440
|
-
});
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### Verifying Hash Correctness
|
|
444
|
-
|
|
445
|
-
```typescript
|
|
446
|
-
import { md5Core } from 'pure-md5';
|
|
447
|
-
import { MD5Stream } from 'pure-md5';
|
|
448
|
-
|
|
449
|
-
const testString = 'The quick brown fox jumps over the lazy dog';
|
|
450
|
-
const expectedHash = md5Core(testString); // Known correct MD5
|
|
451
|
-
|
|
452
|
-
const stream = new MD5Stream();
|
|
453
|
-
stream.on('md5', (result) => {
|
|
454
|
-
console.log('Expected:', expectedHash);
|
|
455
|
-
console.log('Got: ', result.digest);
|
|
456
|
-
console.log('Match: ', result.digest === expectedHash);
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
stream.end(testString);
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Testing with Known Values
|
|
463
|
-
|
|
464
|
-
```
|
|
465
|
-
MD5("") = d41d8cd98f00b204e9800998ecf8427e
|
|
466
|
-
MD5("a") = 0cc175b9c0f1b6a831c399e269772661
|
|
467
|
-
MD5("abc") = 900150983cd24fb0d6963f7d28e17f72
|
|
468
|
-
MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0
|
|
469
|
-
MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
Use these to verify your implementation:
|
|
473
|
-
|
|
474
|
-
```typescript
|
|
475
|
-
const testCases = [
|
|
476
|
-
{ input: '', expected: 'd41d8cd98f00b204e9800998ecf8427e' },
|
|
477
|
-
{ input: 'a', expected: '0cc175b9c0f1b6a831c399e269772661' },
|
|
478
|
-
{ input: 'abc', expected: '900150983cd24fb0d6963f7d28e17f72' },
|
|
479
|
-
];
|
|
480
|
-
|
|
481
|
-
for (const test of testCases) {
|
|
482
|
-
const stream = new MD5Stream();
|
|
483
|
-
stream.on('md5', (result) => {
|
|
484
|
-
const pass = result.digest === test.expected;
|
|
485
|
-
console.log(`Test "${test.input}": ${pass ? 'PASS' : 'FAIL'}`);
|
|
486
|
-
});
|
|
487
|
-
stream.end(test.input);
|
|
488
|
-
}
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
---
|
|
492
|
-
|
|
493
|
-
## Best Practices
|
|
494
|
-
|
|
495
|
-
1. **Always handle errors:**
|
|
496
|
-
```typescript
|
|
497
|
-
stream.on('error', (error) => console.error(error));
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
2. **End streams properly:**
|
|
501
|
-
```typescript
|
|
502
|
-
stream.end(); // Always call end()
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
3. **Check data consistency:**
|
|
506
|
-
```typescript
|
|
507
|
-
console.log('Expected:', expected);
|
|
508
|
-
console.log('Got: ', result.digest);
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
4. **Use appropriate chunk sizes:**
|
|
512
|
-
```typescript
|
|
513
|
-
// 64KB is optimal for most cases
|
|
514
|
-
const chunkSize = 64 * 1024;
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
5. **Reuse streams when appropriate:**
|
|
518
|
-
```typescript
|
|
519
|
-
const stream = new MD5Stream();
|
|
520
|
-
// ... use stream
|
|
521
|
-
stream.reset();
|
|
522
|
-
// ... use again
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
---
|
|
526
|
-
|
|
527
|
-
## Getting Help
|
|
528
|
-
|
|
529
|
-
If you're still having issues:
|
|
530
|
-
|
|
531
|
-
1. Check this troubleshooting guide
|
|
532
|
-
2. Review the [API documentation](STREAM_API.md)
|
|
533
|
-
3. Check existing tests in `__tests__/stream/`
|
|
534
|
-
4. Open an issue with:
|
|
535
|
-
- Your code example
|
|
536
|
-
- Expected vs actual behavior
|
|
537
|
-
- Environment details (Node.js version, browser, OS)
|