@storacha/encrypt-upload-client 1.1.56 → 1.1.58
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/dist/config/constants.d.ts +3 -3
- package/dist/config/constants.js +4 -3
- package/dist/config/env.d.ts +9 -6
- package/dist/config/service.d.ts +13 -13
- package/dist/core/client.d.ts +54 -41
- package/dist/core/client.js +68 -56
- package/dist/core/errors.d.ts +6 -6
- package/dist/core/metadata/encrypted-metadata.d.ts +13 -8
- package/dist/core/metadata/kms-metadata.d.ts +68 -36
- package/dist/core/metadata/lit-metadata.d.ts +63 -28
- package/dist/crypto/adapters/kms-crypto-adapter.d.ts +172 -137
- package/dist/crypto/adapters/lit-crypto-adapter.d.ts +107 -86
- package/dist/crypto/factories.browser.d.ts +9 -5
- package/dist/crypto/factories.browser.js +15 -7
- package/dist/crypto/factories.node.d.ts +13 -6
- package/dist/crypto/factories.node.js +19 -13
- package/dist/crypto/index.d.ts +5 -5
- package/dist/crypto/index.js +5 -5
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.d.ts +58 -54
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.js +174 -146
- package/dist/crypto/symmetric/node-aes-cbc-crypto.d.ts +36 -32
- package/dist/crypto/symmetric/node-aes-cbc-crypto.js +101 -95
- package/dist/examples/decrypt-test.d.ts +2 -2
- package/dist/examples/decrypt-test.js +78 -69
- package/dist/examples/encrypt-test.d.ts +5 -3
- package/dist/examples/encrypt-test.js +58 -55
- package/dist/handlers/decrypt-handler.d.ts +19 -5
- package/dist/handlers/encrypt-handler.d.ts +9 -3
- package/dist/handlers/encrypt-handler.js +93 -57
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/protocols/lit.d.ts +33 -9
- package/dist/protocols/lit.js +134 -98
- package/dist/test/cid-verification.spec.d.ts +2 -2
- package/dist/test/cid-verification.spec.js +341 -313
- package/dist/test/crypto-compatibility.spec.d.ts +2 -2
- package/dist/test/crypto-compatibility.spec.js +184 -120
- package/dist/test/crypto-counter-security.spec.d.ts +2 -2
- package/dist/test/crypto-counter-security.spec.js +177 -138
- package/dist/test/crypto-streaming.spec.d.ts +2 -2
- package/dist/test/crypto-streaming.spec.js +208 -126
- package/dist/test/encrypted-metadata.spec.d.ts +2 -2
- package/dist/test/encrypted-metadata.spec.js +89 -62
- package/dist/test/factories.spec.d.ts +2 -2
- package/dist/test/factories.spec.js +275 -139
- package/dist/test/file-metadata.spec.d.ts +2 -2
- package/dist/test/file-metadata.spec.js +472 -416
- package/dist/test/fixtures/test-fixtures.d.ts +25 -20
- package/dist/test/fixtures/test-fixtures.js +61 -53
- package/dist/test/helpers/test-file-utils.d.ts +19 -14
- package/dist/test/helpers/test-file-utils.js +78 -76
- package/dist/test/https-enforcement.spec.d.ts +2 -2
- package/dist/test/https-enforcement.spec.js +278 -124
- package/dist/test/kms-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/kms-crypto-adapter.spec.js +473 -304
- package/dist/test/lit-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/lit-crypto-adapter.spec.js +206 -118
- package/dist/test/memory-efficiency.spec.d.ts +2 -2
- package/dist/test/memory-efficiency.spec.js +100 -87
- package/dist/test/mocks/key-manager.d.ts +71 -38
- package/dist/test/mocks/key-manager.js +129 -113
- package/dist/test/node-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/node-crypto-adapter.spec.js +155 -102
- package/dist/test/node-generic-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/node-generic-crypto-adapter.spec.js +134 -94
- package/dist/test/setup.d.ts +2 -2
- package/dist/test/setup.js +8 -9
- package/dist/tsconfig.spec.tsbuildinfo +1 -1
- package/dist/types.d.ts +219 -181
- package/dist/utils/file-metadata.d.ts +19 -13
- package/dist/utils.d.ts +14 -5
- package/package.json +4 -4
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {}
|
|
2
|
-
//# sourceMappingURL=lit-crypto-adapter.spec.d.ts.map
|
|
1
|
+
export {}
|
|
2
|
+
//# sourceMappingURL=lit-crypto-adapter.spec.d.ts.map
|
|
@@ -1,120 +1,208 @@
|
|
|
1
|
-
import './setup.js'
|
|
2
|
-
import { test, describe } from 'node:test'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
5
|
-
import { NodeAesCbcCrypto } from '../src/crypto/symmetric/node-aes-cbc-crypto.js'
|
|
6
|
-
import { LitCryptoAdapter } from '../src/crypto/adapters/lit-crypto-adapter.js'
|
|
7
|
-
import {
|
|
1
|
+
import './setup.js'
|
|
2
|
+
import { test, describe } from 'node:test'
|
|
3
|
+
import assert from 'node:assert'
|
|
4
|
+
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
5
|
+
import { NodeAesCbcCrypto } from '../src/crypto/symmetric/node-aes-cbc-crypto.js'
|
|
6
|
+
import { LitCryptoAdapter } from '../src/crypto/adapters/lit-crypto-adapter.js'
|
|
7
|
+
import {
|
|
8
|
+
stringToUint8Array,
|
|
9
|
+
streamToUint8Array,
|
|
10
|
+
uint8ArrayToString,
|
|
11
|
+
} from './helpers/test-file-utils.js'
|
|
8
12
|
// Mock Lit client - cast to any for testing
|
|
9
|
-
const mockLitClient = /** @type {any} */ (
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
const mockLitClient = /** @type {any} */ (
|
|
14
|
+
{
|
|
15
|
+
// Add mock methods as needed
|
|
16
|
+
}
|
|
17
|
+
)
|
|
12
18
|
await describe('LitCryptoAdapter', async () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
19
|
+
await describe('Generic AES-CTR Crypto Implementation', async () => {
|
|
20
|
+
await test('should delegate symmetric crypto operations to the generic implementation', async () => {
|
|
21
|
+
const symmetricCrypto = new GenericAesCtrStreamingCrypto()
|
|
22
|
+
const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient)
|
|
23
|
+
const originalText = 'Op, this is a test for strategy-based encryption!'
|
|
24
|
+
const blob = new Blob([stringToUint8Array(originalText)])
|
|
25
|
+
// Test that it delegates to the symmetric crypto implementation
|
|
26
|
+
const { key, iv, encryptedStream } = await adapter.encryptStream(blob)
|
|
27
|
+
assert(key instanceof Uint8Array, 'Key should be a Uint8Array')
|
|
28
|
+
assert(iv instanceof Uint8Array, 'IV should be a Uint8Array')
|
|
29
|
+
assert(
|
|
30
|
+
encryptedStream instanceof ReadableStream,
|
|
31
|
+
'Encrypted stream should be a ReadableStream'
|
|
32
|
+
)
|
|
33
|
+
// Test decryption delegation
|
|
34
|
+
const decryptedStream = await adapter.decryptStream(
|
|
35
|
+
encryptedStream,
|
|
36
|
+
key,
|
|
37
|
+
iv
|
|
38
|
+
)
|
|
39
|
+
const decryptedBytes = await streamToUint8Array(decryptedStream)
|
|
40
|
+
const decryptedText = uint8ArrayToString(decryptedBytes)
|
|
41
|
+
assert.strictEqual(
|
|
42
|
+
decryptedText,
|
|
43
|
+
originalText,
|
|
44
|
+
'Decrypted text should match original'
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
await test('should initialize Generic Lit adapter with correct configuration', async () => {
|
|
48
|
+
const symmetricCrypto = new GenericAesCtrStreamingCrypto()
|
|
49
|
+
const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient)
|
|
50
|
+
// Test that the adapter has the required methods
|
|
51
|
+
assert(
|
|
52
|
+
typeof adapter.encryptSymmetricKey === 'function',
|
|
53
|
+
'encryptSymmetricKey should be a function'
|
|
54
|
+
)
|
|
55
|
+
assert(
|
|
56
|
+
typeof adapter.decryptSymmetricKey === 'function',
|
|
57
|
+
'decryptSymmetricKey should be a function'
|
|
58
|
+
)
|
|
59
|
+
// Verify adapter has the lit client
|
|
60
|
+
assert.strictEqual(
|
|
61
|
+
adapter.litClient,
|
|
62
|
+
mockLitClient,
|
|
63
|
+
'Adapter should store the Lit client'
|
|
64
|
+
)
|
|
65
|
+
// Verify it uses the correct crypto implementation
|
|
66
|
+
assert(
|
|
67
|
+
adapter.symmetricCrypto instanceof GenericAesCtrStreamingCrypto,
|
|
68
|
+
'Should use GenericAesCtrStreamingCrypto'
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
await describe('Node.js AES-CBC Crypto Implementation (Legacy)', async () => {
|
|
73
|
+
await test('should delegate symmetric crypto operations to the Node.js implementation', async () => {
|
|
74
|
+
const symmetricCrypto = new NodeAesCbcCrypto()
|
|
75
|
+
const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient)
|
|
76
|
+
const originalText = 'Op, this is a test for legacy Node.js encryption!'
|
|
77
|
+
const blob = new Blob([stringToUint8Array(originalText)])
|
|
78
|
+
// Test that it delegates to the symmetric crypto implementation
|
|
79
|
+
const { key, iv, encryptedStream } = await adapter.encryptStream(blob)
|
|
80
|
+
assert(key instanceof Uint8Array, 'Key should be a Uint8Array')
|
|
81
|
+
assert(iv instanceof Uint8Array, 'IV should be a Uint8Array')
|
|
82
|
+
assert(
|
|
83
|
+
encryptedStream instanceof ReadableStream,
|
|
84
|
+
'Encrypted stream should be a ReadableStream'
|
|
85
|
+
)
|
|
86
|
+
// Test decryption delegation
|
|
87
|
+
const decryptedStream = await adapter.decryptStream(
|
|
88
|
+
encryptedStream,
|
|
89
|
+
key,
|
|
90
|
+
iv
|
|
91
|
+
)
|
|
92
|
+
const decryptedBytes = await streamToUint8Array(decryptedStream)
|
|
93
|
+
const decryptedText = uint8ArrayToString(decryptedBytes)
|
|
94
|
+
assert.strictEqual(
|
|
95
|
+
decryptedText,
|
|
96
|
+
originalText,
|
|
97
|
+
'Decrypted text should match original'
|
|
98
|
+
)
|
|
99
|
+
})
|
|
100
|
+
await test('should initialize Node.js Lit adapter with correct configuration', async () => {
|
|
101
|
+
const symmetricCrypto = new NodeAesCbcCrypto()
|
|
102
|
+
const adapter = new LitCryptoAdapter(symmetricCrypto, mockLitClient)
|
|
103
|
+
// Test that the adapter has the required methods
|
|
104
|
+
assert(
|
|
105
|
+
typeof adapter.encryptSymmetricKey === 'function',
|
|
106
|
+
'encryptSymmetricKey should be a function'
|
|
107
|
+
)
|
|
108
|
+
assert(
|
|
109
|
+
typeof adapter.decryptSymmetricKey === 'function',
|
|
110
|
+
'decryptSymmetricKey should be a function'
|
|
111
|
+
)
|
|
112
|
+
// Verify adapter has the lit client
|
|
113
|
+
assert.strictEqual(
|
|
114
|
+
adapter.litClient,
|
|
115
|
+
mockLitClient,
|
|
116
|
+
'Adapter should store the Lit client'
|
|
117
|
+
)
|
|
118
|
+
// Verify it uses the correct crypto implementation
|
|
119
|
+
assert(
|
|
120
|
+
adapter.symmetricCrypto instanceof NodeAesCbcCrypto,
|
|
121
|
+
'Should use NodeAesCbcCrypto'
|
|
122
|
+
)
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
await describe('Cross-Implementation Compatibility', async () => {
|
|
126
|
+
await test('should demonstrate algorithm differences between implementations', async () => {
|
|
127
|
+
const genericCrypto = new GenericAesCtrStreamingCrypto()
|
|
128
|
+
const nodeCrypto = new NodeAesCbcCrypto()
|
|
129
|
+
const genericAdapter = new LitCryptoAdapter(genericCrypto, mockLitClient)
|
|
130
|
+
const nodeAdapter = new LitCryptoAdapter(nodeCrypto, mockLitClient)
|
|
131
|
+
const originalText = 'Test data for algorithm comparison'
|
|
132
|
+
const blob = new Blob([stringToUint8Array(originalText)])
|
|
133
|
+
// Encrypt with both adapters
|
|
134
|
+
const genericResult = await genericAdapter.encryptStream(blob)
|
|
135
|
+
const nodeResult = await nodeAdapter.encryptStream(blob)
|
|
136
|
+
// Convert streams to bytes
|
|
137
|
+
const genericEncrypted = await streamToUint8Array(
|
|
138
|
+
genericResult.encryptedStream
|
|
139
|
+
)
|
|
140
|
+
const nodeEncrypted = await streamToUint8Array(nodeResult.encryptedStream)
|
|
141
|
+
// Verify they produce different results (different algorithms)
|
|
142
|
+
assert.notDeepEqual(
|
|
143
|
+
genericEncrypted,
|
|
144
|
+
nodeEncrypted,
|
|
145
|
+
'AES-CTR and AES-CBC should produce different encrypted outputs'
|
|
146
|
+
)
|
|
147
|
+
// Verify both can decrypt their own data
|
|
148
|
+
const genericDecryptStream = new ReadableStream({
|
|
149
|
+
start(controller) {
|
|
150
|
+
controller.enqueue(genericEncrypted)
|
|
151
|
+
controller.close()
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
const nodeDecryptStream = new ReadableStream({
|
|
155
|
+
start(controller) {
|
|
156
|
+
controller.enqueue(nodeEncrypted)
|
|
157
|
+
controller.close()
|
|
158
|
+
},
|
|
159
|
+
})
|
|
160
|
+
const genericDecrypted = await genericAdapter.decryptStream(
|
|
161
|
+
genericDecryptStream,
|
|
162
|
+
genericResult.key,
|
|
163
|
+
genericResult.iv
|
|
164
|
+
)
|
|
165
|
+
const nodeDecrypted = await nodeAdapter.decryptStream(
|
|
166
|
+
nodeDecryptStream,
|
|
167
|
+
nodeResult.key,
|
|
168
|
+
nodeResult.iv
|
|
169
|
+
)
|
|
170
|
+
const genericDecryptedBytes = await streamToUint8Array(genericDecrypted)
|
|
171
|
+
const nodeDecryptedBytes = await streamToUint8Array(nodeDecrypted)
|
|
172
|
+
// Both should decrypt to the same original text
|
|
173
|
+
assert.strictEqual(
|
|
174
|
+
uint8ArrayToString(genericDecryptedBytes),
|
|
175
|
+
originalText,
|
|
176
|
+
'Generic adapter should decrypt correctly'
|
|
177
|
+
)
|
|
178
|
+
assert.strictEqual(
|
|
179
|
+
uint8ArrayToString(nodeDecryptedBytes),
|
|
180
|
+
originalText,
|
|
181
|
+
'Node adapter should decrypt correctly'
|
|
182
|
+
)
|
|
183
|
+
console.log(
|
|
184
|
+
'Both crypto implementations work with Lit adapter but produce different encrypted outputs'
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
await test('should verify factory function behavior', async () => {
|
|
188
|
+
const { createGenericLitAdapter, createNodeLitAdapter } = await import(
|
|
189
|
+
'../src/crypto/factories.node.js'
|
|
190
|
+
)
|
|
191
|
+
const genericAdapter = createGenericLitAdapter(mockLitClient)
|
|
192
|
+
const nodeAdapter = createNodeLitAdapter(mockLitClient)
|
|
193
|
+
// Verify factory functions create adapters with correct crypto implementations
|
|
194
|
+
assert(
|
|
195
|
+
genericAdapter.symmetricCrypto instanceof GenericAesCtrStreamingCrypto,
|
|
196
|
+
'Generic factory should create adapter with GenericAesCtrStreamingCrypto'
|
|
197
|
+
)
|
|
198
|
+
assert(
|
|
199
|
+
nodeAdapter.symmetricCrypto instanceof NodeAesCbcCrypto,
|
|
200
|
+
'Node factory should create adapter with NodeAesCbcCrypto'
|
|
201
|
+
)
|
|
202
|
+
console.log(
|
|
203
|
+
'Factory functions create adapters with correct crypto implementations'
|
|
204
|
+
)
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
//# sourceMappingURL=lit-crypto-adapter.spec.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {}
|
|
2
|
-
//# sourceMappingURL=memory-efficiency.spec.d.ts.map
|
|
1
|
+
export {}
|
|
2
|
+
//# sourceMappingURL=memory-efficiency.spec.d.ts.map
|
|
@@ -1,93 +1,106 @@
|
|
|
1
|
-
import './setup.js'
|
|
2
|
-
import { test, describe } from 'node:test'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
5
|
-
import { createTestFile } from './helpers/test-file-utils.js'
|
|
1
|
+
import './setup.js'
|
|
2
|
+
import { test, describe } from 'node:test'
|
|
3
|
+
import assert from 'node:assert'
|
|
4
|
+
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
5
|
+
import { createTestFile } from './helpers/test-file-utils.js'
|
|
6
6
|
/**
|
|
7
7
|
* These tests demonstrate why streaming is necessary for large files.
|
|
8
8
|
* They show that buffered approaches fail with memory errors while streaming succeeds.
|
|
9
9
|
*/
|
|
10
10
|
await describe('Memory Efficiency - Why Streaming Matters', async () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
chunkCount++;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
finally {
|
|
34
|
-
reader.releaseLock();
|
|
35
|
-
}
|
|
36
|
-
const processingTime = Date.now() - startTime;
|
|
37
|
-
const throughput = processedBytes / 1024 / 1024 / (processingTime / 1000); // MB/s
|
|
38
|
-
assert.strictEqual(processedBytes, testFile.size, `Should process entire ${sizeMB}MB file`);
|
|
39
|
-
console.log(`✓ ${sizeMB}MB: ${chunkCount} chunks, ${throughput.toFixed(1)} MB/s`);
|
|
11
|
+
await test('should show streaming handles progressively larger files', async () => {
|
|
12
|
+
const streamingCrypto = new GenericAesCtrStreamingCrypto()
|
|
13
|
+
// Test with multiple sizes to show streaming scales linearly
|
|
14
|
+
const testSizes = [5, 10, 15, 20, 50, 100, 500, 1000] // MB - sizes that would challenge buffered approaches
|
|
15
|
+
for (const sizeMB of testSizes) {
|
|
16
|
+
console.log(`Processing ${sizeMB}MB file...`)
|
|
17
|
+
const testFile = createTestFile(sizeMB)
|
|
18
|
+
const startTime = Date.now()
|
|
19
|
+
const { encryptedStream } = await streamingCrypto.encryptStream(testFile)
|
|
20
|
+
let processedBytes = 0
|
|
21
|
+
let chunkCount = 0
|
|
22
|
+
const reader = encryptedStream.getReader()
|
|
23
|
+
try {
|
|
24
|
+
// eslint-disable-next-line no-constant-condition
|
|
25
|
+
while (true) {
|
|
26
|
+
const { done, value } = await reader.read()
|
|
27
|
+
if (done) break
|
|
28
|
+
processedBytes += value.length
|
|
29
|
+
chunkCount++
|
|
40
30
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
31
|
+
} finally {
|
|
32
|
+
reader.releaseLock()
|
|
33
|
+
}
|
|
34
|
+
const processingTime = Date.now() - startTime
|
|
35
|
+
const throughput = processedBytes / 1024 / 1024 / (processingTime / 1000) // MB/s
|
|
36
|
+
assert.strictEqual(
|
|
37
|
+
processedBytes,
|
|
38
|
+
testFile.size,
|
|
39
|
+
`Should process entire ${sizeMB}MB file`
|
|
40
|
+
)
|
|
41
|
+
console.log(
|
|
42
|
+
`✓ ${sizeMB}MB: ${chunkCount} chunks, ${throughput.toFixed(1)} MB/s`
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
console.log(
|
|
46
|
+
'DEMONSTRATED: Streaming handles large files with consistent performance'
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
await test('should project memory behavior for realistic file sizes', async () => {
|
|
50
|
+
const streamingCrypto = new GenericAesCtrStreamingCrypto()
|
|
51
|
+
// Test with a size we can actually handle to project larger files
|
|
52
|
+
const testFile = createTestFile(5) // 5MB
|
|
53
|
+
const getMemoryUsage = () => {
|
|
54
|
+
if (globalThis.gc) globalThis.gc()
|
|
55
|
+
return process.memoryUsage ? process.memoryUsage().heapUsed : 0
|
|
56
|
+
}
|
|
57
|
+
const baseMemory = getMemoryUsage()
|
|
58
|
+
const { encryptedStream } = await streamingCrypto.encryptStream(testFile)
|
|
59
|
+
let peakMemoryDelta = 0
|
|
60
|
+
let processedBytes = 0
|
|
61
|
+
const reader = encryptedStream.getReader()
|
|
62
|
+
try {
|
|
63
|
+
// eslint-disable-next-line no-constant-condition
|
|
64
|
+
while (true) {
|
|
65
|
+
const { done, value } = await reader.read()
|
|
66
|
+
if (done) break
|
|
67
|
+
processedBytes += value.length
|
|
68
|
+
// Sample memory usage
|
|
69
|
+
const currentMemory = getMemoryUsage()
|
|
70
|
+
const memoryDelta = currentMemory - baseMemory
|
|
71
|
+
peakMemoryDelta = Math.max(peakMemoryDelta, memoryDelta)
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
reader.releaseLock()
|
|
75
|
+
}
|
|
76
|
+
const peakMemoryMB = peakMemoryDelta / 1024 / 1024
|
|
77
|
+
const fileSize = testFile.size / 1024 / 1024
|
|
78
|
+
const memoryEfficiency = (peakMemoryDelta / testFile.size) * 100
|
|
79
|
+
console.log(`File size: ${fileSize.toFixed(1)}MB`)
|
|
80
|
+
console.log(`Peak memory delta: ${peakMemoryMB.toFixed(2)}MB`)
|
|
81
|
+
console.log(
|
|
82
|
+
`Memory efficiency: ${memoryEfficiency.toFixed(1)}% of file size`
|
|
83
|
+
)
|
|
84
|
+
// Project to larger file sizes
|
|
85
|
+
console.log('\nProjected memory usage:')
|
|
86
|
+
const projectedSizes = [100, 1000, 5000] // MB = 100MB, 1GB, 5GB
|
|
87
|
+
for (const sizeMB of projectedSizes) {
|
|
88
|
+
const projectedMemory = (memoryEfficiency / 100) * sizeMB
|
|
89
|
+
const sizeLabel = sizeMB >= 1000 ? `${sizeMB / 1000}GB` : `${sizeMB}MB`
|
|
90
|
+
console.log(` ${sizeLabel}: ~${projectedMemory.toFixed(1)}MB memory`)
|
|
91
|
+
}
|
|
92
|
+
// Memory should be bounded (much less than file size)
|
|
93
|
+
assert(
|
|
94
|
+
peakMemoryMB < fileSize,
|
|
95
|
+
'Streaming should use less memory than file size'
|
|
96
|
+
)
|
|
97
|
+
assert(
|
|
98
|
+
memoryEfficiency < 50,
|
|
99
|
+
'Memory usage should be less than 50% of file size'
|
|
100
|
+
)
|
|
101
|
+
console.log(
|
|
102
|
+
'DEMONSTRATED: Streaming memory usage scales sub-linearly with file size'
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
//# sourceMappingURL=memory-efficiency.spec.js.map
|