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.
Files changed (177) hide show
  1. package/README.md +38 -24
  2. package/dist/adapters/ie11.cjs +1 -2
  3. package/dist/adapters/ie11.js +1 -2
  4. package/dist/adapters/node.cjs +1 -2
  5. package/dist/adapters/node.js +1 -2
  6. package/dist/adapters/webcrypto.cjs +1 -2
  7. package/dist/adapters/webcrypto.js +1 -2
  8. package/dist/index.cjs +1 -2
  9. package/dist/index.d.ts +149 -5
  10. package/dist/index.js +3 -2
  11. package/dist/md5.cjs +1 -0
  12. package/dist/md5.d.ts +20 -0
  13. package/dist/md5.js +1 -0
  14. package/dist/stream/md5-stream.cjs +1 -2
  15. package/dist/stream/md5-stream.js +1 -2
  16. package/dist/stream/whatwg-stream.cjs +1 -2
  17. package/dist/stream/whatwg-stream.js +1 -2
  18. package/dist/utils/detect.cjs +1 -2
  19. package/dist/utils/detect.js +3 -2
  20. package/package.json +10 -15
  21. package/pure-md5-0.2.1.tgz +0 -0
  22. package/test-tree-shake.mjs +12 -0
  23. package/.aliases +0 -19
  24. package/.bash_profile +0 -12
  25. package/.bash_prompt +0 -56
  26. package/.changeset/README.md +0 -32
  27. package/.changeset/config.json +0 -16
  28. package/.continue/mcpServers/new-mcp-server.yaml +0 -10
  29. package/.continue/rules +0 -29
  30. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  31. package/.github/ISSUE_TEMPLATE/documentation.md +0 -20
  32. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  33. package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
  34. package/.github/workflows/npm-publish.yml +0 -33
  35. package/.github/workflows/release.yml +0 -42
  36. package/CHANGELOG.md +0 -9
  37. package/CONTRIBUTING.md +0 -203
  38. package/MIGRATION_GUIDE_STREAMS.md +0 -374
  39. package/STREAM_API.md +0 -582
  40. package/STREAM_BENCHMARKS.md +0 -232
  41. package/STREAM_EXAMPLES.md +0 -669
  42. package/STREAM_OPTIMIZATION_REPORT.md +0 -136
  43. package/STREAM_TROUBLESHOOTING.md +0 -537
  44. package/WEB_CRYPTO_TESTS_SUMMARY.md +0 -140
  45. package/WHATWG_STREAMS.md +0 -191
  46. package/__tests__/adapters/node-crypto.test.ts +0 -167
  47. package/__tests__/adapters/web-crypto-node.test.ts +0 -73
  48. package/__tests__/adapters/web-crypto.test.ts +0 -195
  49. package/__tests__/add32.test.ts +0 -33
  50. package/__tests__/fallback.test.ts +0 -345
  51. package/__tests__/hex.test.ts +0 -38
  52. package/__tests__/hex_chr.test.ts +0 -20
  53. package/__tests__/index.test.ts +0 -87
  54. package/__tests__/integration/fixtures/test-file.txt +0 -1
  55. package/__tests__/integration/md5-stream-file.test.ts +0 -293
  56. package/__tests__/integration/node-crypto-file.test.ts +0 -86
  57. package/__tests__/integration/web-crypto.test.ts +0 -38
  58. package/__tests__/md51.test.ts +0 -73
  59. package/__tests__/md5block.test.ts +0 -61
  60. package/__tests__/md5cycle.test.ts +0 -48
  61. package/__tests__/round-functions.test.ts +0 -87
  62. package/__tests__/stream/fs-utils.test.ts +0 -209
  63. package/__tests__/stream/md5-stream-edge-cases.test.ts +0 -461
  64. package/__tests__/stream/md5-stream.test.ts +0 -418
  65. package/__tests__/stream/whatwg-stream.test.ts +0 -355
  66. package/__tests__/stream/whatwg-stream.test.ts.bak2 +0 -335
  67. package/benchmarks/md5-stream.bench.ts +0 -212
  68. package/benchmarks/whatwg-stream.bench.ts +0 -180
  69. package/dist/adapters/ie11.cjs.map +0 -1
  70. package/dist/adapters/ie11.js.map +0 -1
  71. package/dist/adapters/node.cjs.map +0 -1
  72. package/dist/adapters/node.js.map +0 -1
  73. package/dist/adapters/webcrypto.cjs.map +0 -1
  74. package/dist/adapters/webcrypto.js.map +0 -1
  75. package/dist/chunk-2YXXFGBV.js +0 -2
  76. package/dist/chunk-2YXXFGBV.js.map +0 -1
  77. package/dist/chunk-4KSCMS4Q.js +0 -2
  78. package/dist/chunk-4KSCMS4Q.js.map +0 -1
  79. package/dist/chunk-6P2QV5SR.js +0 -4
  80. package/dist/chunk-6P2QV5SR.js.map +0 -1
  81. package/dist/chunk-G5WHEAIQ.js +0 -2
  82. package/dist/chunk-G5WHEAIQ.js.map +0 -1
  83. package/dist/chunk-H2K353LR.js +0 -2
  84. package/dist/chunk-H2K353LR.js.map +0 -1
  85. package/dist/chunk-JKVD5LHZ.js +0 -2
  86. package/dist/chunk-JKVD5LHZ.js.map +0 -1
  87. package/dist/chunk-NWQ4N5RX.js +0 -2
  88. package/dist/chunk-NWQ4N5RX.js.map +0 -1
  89. package/dist/chunk-PHZ7FTYF.js +0 -2
  90. package/dist/chunk-PHZ7FTYF.js.map +0 -1
  91. package/dist/chunk-PNZTVQA7.js +0 -2
  92. package/dist/chunk-PNZTVQA7.js.map +0 -1
  93. package/dist/chunk-R4JB5MBR.js +0 -2
  94. package/dist/chunk-R4JB5MBR.js.map +0 -1
  95. package/dist/chunk-VFOAY6XI.js +0 -2
  96. package/dist/chunk-VFOAY6XI.js.map +0 -1
  97. package/dist/chunk-XB5BQIEX.js +0 -2
  98. package/dist/chunk-XB5BQIEX.js.map +0 -1
  99. package/dist/core/index.cjs +0 -2
  100. package/dist/core/index.cjs.map +0 -1
  101. package/dist/core/index.d.cts +0 -19
  102. package/dist/core/index.d.ts +0 -19
  103. package/dist/core/index.js +0 -2
  104. package/dist/core/index.js.map +0 -1
  105. package/dist/index.cjs.map +0 -1
  106. package/dist/index.d.cts +0 -84
  107. package/dist/index.js.map +0 -1
  108. package/dist/stream/adapter.cjs +0 -2
  109. package/dist/stream/adapter.cjs.map +0 -1
  110. package/dist/stream/adapter.d.cts +0 -63
  111. package/dist/stream/adapter.d.ts +0 -63
  112. package/dist/stream/adapter.js +0 -2
  113. package/dist/stream/adapter.js.map +0 -1
  114. package/dist/stream/fs-utils.cjs +0 -2
  115. package/dist/stream/fs-utils.cjs.map +0 -1
  116. package/dist/stream/fs-utils.d.cts +0 -137
  117. package/dist/stream/fs-utils.d.ts +0 -137
  118. package/dist/stream/fs-utils.js +0 -2
  119. package/dist/stream/fs-utils.js.map +0 -1
  120. package/dist/stream/index.cjs +0 -2
  121. package/dist/stream/index.cjs.map +0 -1
  122. package/dist/stream/index.d.cts +0 -4
  123. package/dist/stream/index.d.ts +0 -4
  124. package/dist/stream/index.js +0 -2
  125. package/dist/stream/index.js.map +0 -1
  126. package/dist/stream/light/index.cjs +0 -2
  127. package/dist/stream/light/index.cjs.map +0 -1
  128. package/dist/stream/light/index.d.cts +0 -4
  129. package/dist/stream/light/index.d.ts +0 -4
  130. package/dist/stream/light/index.js +0 -2
  131. package/dist/stream/light/index.js.map +0 -1
  132. package/dist/stream/md5-stream.cjs.map +0 -1
  133. package/dist/stream/md5-stream.js.map +0 -1
  134. package/dist/stream/whatwg-stream.cjs.map +0 -1
  135. package/dist/stream/whatwg-stream.js.map +0 -1
  136. package/dist/types-edGoGJ5V.d.cts +0 -42
  137. package/dist/types-edGoGJ5V.d.ts +0 -42
  138. package/dist/utils/detect.cjs.map +0 -1
  139. package/dist/utils/detect.js.map +0 -1
  140. package/planning/03-optimization-size-tree-shaking/01-es-modules-tree-shaking.md +0 -152
  141. package/planning/03-optimization-size-tree-shaking/02-consolidate-modules.md +0 -65
  142. package/planning/03-optimization-size-tree-shaking/03-remove-duplicate-add32.md +0 -93
  143. package/planning/03-optimization-size-tree-shaking/04-remove-runtime-check.md +0 -102
  144. package/planning/03-optimization-size-tree-shaking/05-optimize-loops-performance.md +0 -107
  145. package/planning/03-optimization-size-tree-shaking/06-tsup-formats-configuration.md +0 -227
  146. package/planning/03-optimization-size-tree-shaking/07-multiple-build-formats.md +0 -228
  147. package/planning/03-optimization-size-tree-shaking/08-benchmarks-metrics.md +0 -34
  148. package/planning/03-optimization-size-tree-shaking/MIGRATION_GUIDE.md +0 -260
  149. package/planning/03-optimization-size-tree-shaking/README.md +0 -173
  150. package/planning/03-optimization-size-tree-shaking/SUMMARY.md +0 -168
  151. package/planning/04-adapter-backend/03-backend-web-crypto.md +0 -149
  152. package/planning/04-adapter-backend/04-backend-node-crypto.md +0 -181
  153. package/planning/04-adapter-backend/05-backend-pure-js.md +0 -174
  154. package/planning/04-adapter-backend/06-backend-ie11.md +0 -158
  155. package/planning/04-adapter-backend/07-detection-environment.md +0 -232
  156. package/planning/04-adapter-backend/08-detection-backend.md +0 -210
  157. package/planning/04-adapter-backend/09-adapter-unified.md +0 -255
  158. package/planning/04-adapter-backend/10-fallback-mechanism.md +0 -333
  159. package/planning/04-adapter-backend/11-tests-backend-web-crypto.md +0 -191
  160. package/planning/04-adapter-backend/12-tests-backend-node-crypto.md +0 -222
  161. package/planning/04-adapter-backend/README.md +0 -45
  162. package/planning/05-documentation-publishing/01-README-optimization.md +0 -105
  163. package/planning/05-documentation-publishing/02-VitePress-site-evaluation.md +0 -136
  164. package/planning/05-documentation-publishing/03-Changeset-setup.md +0 -192
  165. package/planning/05-documentation-publishing/04-GitHub-templates.md +0 -252
  166. package/planning/05-documentation-publishing/README.md +0 -22
  167. package/planning/05-documentation-publishing/STATUS.md +0 -222
  168. package/planning/prd.md +0 -405
  169. package/planning/streams/01-create-md5stream-class.md +0 -69
  170. package/planning/streams/02-create-factory-api.md +0 -65
  171. package/planning/streams/03-fs-integration.md +0 -37
  172. package/planning/streams/04-whatwg-streams-support.md +0 -37
  173. package/planning/streams/05-audit-optimization.md +0 -121
  174. package/planning/streams/06-comprehensive-tests-docs.md +0 -137
  175. package/planning/streams/07-architecture-integration.md +0 -38
  176. package/planning/streams/README.md +0 -98
  177. package/tsup.config.ts +0 -24
@@ -1,255 +0,0 @@
1
- # Task 09: Creating Unified Adapter with Unified Interface
2
-
3
- ## Goal
4
-
5
- Создать unified adapter, который объединяет все backend'ы и предоставляет единый API для пользователей.
6
-
7
- ## Implementation
8
-
9
- ### 1. Создать файл src/adapters/unified.ts
10
-
11
- ```typescript
12
- import { PureJSBackend } from './pure-js.js';
13
- import { WebCryptoBackend } from './web-crypto.js';
14
- import { NodeCryptoBackend } from './node-crypto.js';
15
- import { IE11Backend } from './ie11.js';
16
- import { detector } from '../detection/backend-detector.js';
17
-
18
- export interface MD5AdapterOptions {
19
- backend?: string;
20
- fallback?: boolean;
21
- reportFallback?: boolean;
22
- }
23
-
24
- export class MD5Adapter {
25
- private backend: any | null = null;
26
- private backendName: string | null = null;
27
- private options: MD5AdapterOptions;
28
-
29
- constructor(options: MD5AdapterOptions = {}) {
30
- this.options = {
31
- fallback: true,
32
- reportFallback: false,
33
- ...options
34
- };
35
- }
36
-
37
- /**
38
- * Hash string data with automatic backend selection or specified backend
39
- */
40
- async hash(data: string, options?: { backend?: string }): Promise<string> {
41
- const backend = await this.getBackend(options?.backend);
42
- return backend.hash(data);
43
- }
44
-
45
- /**
46
- * Hash binary data (ArrayBuffer, Uint8Array)
47
- */
48
- async hashBinary(data: ArrayBuffer | Uint8Array, options?: { backend?: string }): Promise<string> {
49
- const backend = await this.getBackend(options?.backend);
50
- return backend.hashBinary(data);
51
- }
52
-
53
- /**
54
- * Update hash with additional data (streaming)
55
- */
56
- async update(data: string | ArrayBuffer | Uint8Array, options?: { backend?: string }): Promise<void> {
57
- const backend = await this.getBackend(options?.backend);
58
- backend.update(data);
59
- }
60
-
61
- /**
62
- * Get final hash digest (for streaming)
63
- */
64
- async digest(encoding: 'hex' | 'buffer' = 'hex', options?: { backend?: string }): Promise<string | Uint8Array> {
65
- const backend = await this.getBackend(options?.backend);
66
- return backend.digest(encoding);
67
- }
68
-
69
- /**
70
- * Reset the hash state
71
- */
72
- async reset(options?: { backend?: string }): Promise<void> {
73
- const backend = await this.getBackend(options?.backend);
74
- backend.reset();
75
- }
76
-
77
- /**
78
- * Get backend name
79
- */
80
- async getBackendName(): Promise<string> {
81
- if (!this.backendName) {
82
- const result = await detector.detect();
83
- this.backendName = result.backend;
84
- }
85
- return this.backendName;
86
- }
87
-
88
- /**
89
- * Check if specific backend is available
90
- */
91
- static async isAvailable(backend: string): Promise<boolean> {
92
- const { checkBackendAvailability } = await import('./backend-availability.js');
93
- const result = await checkBackendAvailability(backend);
94
- return result.available;
95
- }
96
-
97
- /**
98
- * Get list of available backends
99
- */
100
- static async getAvailableBackends(): Promise<string[]> {
101
- const { getAllAvailableBackends } = await import('./backend-availability.js');
102
- return getAllAvailableBackends();
103
- }
104
-
105
- /**
106
- * Force specific backend for all operations
107
- */
108
- async useBackend(backendName: string): Promise<void> {
109
- this.backend = await detector.createBackendByName(backendName);
110
- this.backendName = backendName;
111
- }
112
-
113
- /**
114
- * Reset to automatic backend selection
115
- */
116
- async resetBackend(): Promise<void> {
117
- this.backend = null;
118
- this.backendName = null;
119
- }
120
-
121
- /**
122
- * Get backend instance (lazy initialization)
123
- */
124
- private async getBackend(overrideBackend?: string): Promise<any> {
125
- if (overrideBackend) {
126
- return await detector.createBackendByName(overrideBackend);
127
- }
128
-
129
- if (this.backend) {
130
- return this.backend;
131
- }
132
-
133
- this.backend = await detector.createBackend();
134
- this.backendName = await detector.getBackendName();
135
- return this.backend;
136
- }
137
- }
138
-
139
- export const md5 = new MD5Adapter();
140
- ```
141
-
142
- ### 2. Integration с основным API
143
-
144
- В `src/index.ts` обновить экспорт:
145
-
146
- ```typescript
147
- export { md5 } from './adapters/unified.js';
148
-
149
- // Also keep original export
150
- export { default as pureMD5 } from './md51.js';
151
-
152
- // Export backend-related utilities
153
- export { detector } from './detection/backend-detector.js';
154
- export { BackendDetector } from './detection/backend-detector.js';
155
- ```
156
-
157
- ### 3. Упрощенный API для простых случаев
158
-
159
- Создать файл `src/index-simple.ts`:
160
-
161
- ```typescript
162
- import { md5 } from './adapters/unified.js';
163
-
164
- /**
165
- * Simple MD5 hashing function
166
- * @param data - String to hash
167
- * @returns MD5 hash as hex string
168
- */
169
- export async function hash(data: string): Promise<string> {
170
- return md5.hash(data);
171
- }
172
-
173
- /**
174
- * Hash with specific backend
175
- */
176
- export async function hashWithBackend(data: string, backend: string): Promise<string> {
177
- return md5.hash(data, { backend });
178
- }
179
- ```
180
-
181
- ### 4. Tests
182
-
183
- Создать файл `__tests__/adapters/unified.test.ts`:
184
-
185
- ```typescript
186
- describe('MD5Adapter', () => {
187
- let adapter: MD5Adapter;
188
-
189
- beforeAll(() => {
190
- adapter = new MD5Adapter();
191
- });
192
-
193
- it('should hash string with automatic backend', async () => {
194
- const result = await adapter.hash('hello');
195
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
196
- });
197
-
198
- it('should hash with specific backend', async () => {
199
- const result = await adapter.hash('hello', { backend: 'purejs' });
200
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
201
- });
202
-
203
- it('should hash binary data', async () => {
204
- const data = new Uint8Array([104, 101, 108, 108, 111]); // "hello"
205
- const result = await adapter.hashBinary(data);
206
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
207
- });
208
-
209
- it('should support streaming', async () => {
210
- await adapter.update('he');
211
- await adapter.update('l');
212
- await adapter.update('lo');
213
- const result = await adapter.digest('hex');
214
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
215
- });
216
-
217
- it('should reset state', async () => {
218
- await adapter.update('hello');
219
- await adapter.reset();
220
- await adapter.update('world');
221
- const result = await adapter.digest('hex');
222
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
223
- });
224
-
225
- it('should get backend name', async () => {
226
- const name = await adapter.getBackendName();
227
- expect(typeof name).toBe('string');
228
- });
229
-
230
- it('should force specific backend', async () => {
231
- await adapter.useBackend('purejs');
232
- const backendName = await adapter.getBackendName();
233
- expect(backendName).toBe('purejs');
234
- });
235
-
236
- it('should get available backends', async () => {
237
- const backends = await MD5Adapter.getAvailableBackends();
238
- expect(Array.isArray(backends)).toBe(true);
239
- expect(backends.length).toBeGreaterThan(0);
240
- });
241
- });
242
- ```
243
-
244
- ### 5. Documentation
245
-
246
- Добавить JSDoc комментарии для всех публичных методов и классов.
247
-
248
- ## Ожидаемый результат
249
-
250
- - ✅ Unified adapter реализован
251
- - ✅ Единый API для всех backend'ов
252
- - ✅ Support автоматического и принудительного выбора backend
253
- - ✅ Tests проходят успешно
254
- - ✅ Интегрирован в основной API
255
- - ✅ Documentation создана
@@ -1,333 +0,0 @@
1
- # Task 10: Fallback Mechanisms Implementation with Priority Order
2
-
3
- ## Goal
4
-
5
- Implement fallback механизм, который автоматически пробует альтернативные backend'ы при ошибке основного.
6
-
7
- ## Implementation
8
-
9
- ### 1. Создать файл src/adapters/fallback.ts
10
-
11
- ```typescript
12
- import { PureJSBackend } from './pure-js.js';
13
- import { WebCryptoBackend } from './web-crypto.js';
14
- import { NodeCryptoBackend } from './node-crypto.js';
15
- import { IE11Backend } from './ie11.js';
16
- import { BackendDetector } from '../detection/backend-detector.js';
17
-
18
- export interface FallbackResult<T> {
19
- success: boolean;
20
- backend: string;
21
- data: T;
22
- errors?: { backend: string; error: Error }[];
23
- }
24
-
25
- export class FallbackManager {
26
- private detector: BackendDetector;
27
- private fallbackOrder: string[];
28
-
29
- constructor(fallbackOrder: string[] = ['nodecrypto', 'webcrypto', 'ie11', 'purejs']) {
30
- this.detector = new BackendDetector();
31
- this.fallbackOrder = fallbackOrder;
32
- }
33
-
34
- /**
35
- * Execute operation with fallback mechanism
36
- */
37
- async execute<T>(operation: (backend: any) => Promise<T>): Promise<FallbackResult<T>> {
38
- const errors: { backend: string; error: Error }[] = [];
39
-
40
- for (const backendName of this.fallbackOrder) {
41
- try {
42
- const backend = await this.detector.createBackendByName(backendName);
43
- const result = await operation(backend);
44
- return {
45
- success: true,
46
- backend: backendName,
47
- data: result
48
- };
49
- } catch (error) {
50
- errors.push({ backend: backendName, error: error as Error });
51
-
52
- // Don't fallback if last backend failed
53
- if (backendName === this.fallbackOrder[this.fallbackOrder.length - 1]) {
54
- return {
55
- success: false,
56
- backend: backendName,
57
- data: null as unknown as T,
58
- errors
59
- };
60
- }
61
- }
62
- }
63
-
64
- return {
65
- success: false,
66
- backend: '',
67
- data: null as unknown as T,
68
- errors
69
- };
70
- }
71
-
72
- /**
73
- * Hash with fallback mechanism
74
- */
75
- async hash(data: string): Promise<FallbackResult<string>> {
76
- return this.execute(async (backend) => backend.hash(data));
77
- }
78
-
79
- /**
80
- * Hash binary data with fallback
81
- */
82
- async hashBinary(data: ArrayBuffer | Uint8Array): Promise<FallbackResult<string>> {
83
- return this.execute(async (backend) => backend.hashBinary(data));
84
- }
85
-
86
- /**
87
- * Get the best available backend
88
- */
89
- async getBestBackend(): Promise<string> {
90
- const available = await this.getAvailableBackends();
91
- if (available.length === 0) {
92
- return 'purejs'; // Fallback
93
- }
94
- return available[0]; // First is best
95
- }
96
-
97
- /**
98
- * Get available backends in priority order
99
- */
100
- async getAvailableBackends(): Promise<string[]> {
101
- const available: string[] = [];
102
-
103
- for (const backendName of this.fallbackOrder) {
104
- try {
105
- const backend = await this.detector.createBackendByName(backendName);
106
- available.push(backendName);
107
- } catch {
108
- // Backend not available
109
- }
110
- }
111
-
112
- return available;
113
- }
114
-
115
- /**
116
- * Get backend metrics for monitoring
117
- */
118
- getMetrics(): Record<string, { success: number; fail: number }> {
119
- // Implementation for tracking usage
120
- return {};
121
- }
122
- }
123
-
124
- export const fallbackManager = new FallbackManager();
125
- ```
126
-
127
- ### 2. Integration с unified adapter
128
-
129
- Обновить `src/adapters/unified.ts`:
130
-
131
- ```typescript
132
- import { FallbackManager, fallbackManager } from './fallback.js';
133
-
134
- export class MD5Adapter {
135
- private fallbackManager: FallbackManager;
136
-
137
- constructor(options: MD5AdapterOptions = {}) {
138
- this.fallbackManager = options.fallback !== false
139
- ? new FallbackManager()
140
- : null;
141
- }
142
-
143
- async hash(data: string, options?: { backend?: string }): Promise<string> {
144
- if (options?.backend) {
145
- const backend = await this.getBackend(options.backend);
146
- return backend.hash(data);
147
- }
148
-
149
- // Use fallback if enabled
150
- if (this.fallbackManager) {
151
- const result = await this.fallbackManager.hash(data);
152
- if (result.success) {
153
- return result.data;
154
- }
155
- throw new Error(`MD5 hash failed: ${result.errors.map(e => e.error.message).join(', ')}`);
156
- }
157
-
158
- const backend = await this.getBackend();
159
- return backend.hash(data);
160
- }
161
-
162
- // ... остальные методы с fallback
163
- }
164
- ```
165
-
166
- ### 3. Робастная функция хэширования
167
-
168
- Создать файл `src/adapters/robust.ts`:
169
-
170
- ```typescript
171
- import { FallbackManager } from './fallback.js';
172
-
173
- export async function robustHash(
174
- data: string,
175
- options: {
176
- fallback?: boolean;
177
- reportFallback?: boolean;
178
- forceBackend?: string;
179
- } = {}
180
- ): Promise<string> {
181
- const fallbackManager = new FallbackManager();
182
-
183
- if (options.forceBackend) {
184
- // Use specific backend without fallback
185
- const backend = await fallbackManager.detector.createBackendByName(options.forceBackend);
186
- return backend.hash(data);
187
- }
188
-
189
- if (options.fallback === false) {
190
- // Use default backend without fallback
191
- const backend = await fallbackManager.detector.createBackend();
192
- return backend.hash(data);
193
- }
194
-
195
- // Use fallback
196
- const result = await fallbackManager.hash(data);
197
-
198
- if (result.success) {
199
- if (options.reportFallback && result.backend !== 'nodecrypto' && result.backend !== 'webcrypto') {
200
- console.info(`MD5 used fallback backend: ${result.backend}`);
201
- }
202
- return result.data;
203
- }
204
-
205
- // All backends failed
206
- const errorMessage = result.errors
207
- ? result.errors.map(e => `${e.backend}: ${e.error.message}`).join(', ')
208
- : 'All backends failed';
209
-
210
- throw new Error(`MD5 hash failed after all attempts: ${errorMessage}`);
211
- }
212
- ```
213
-
214
- ### 4. Мониторинг fallback механизмов
215
-
216
- Создать файл `src/adapters/metrics.ts`:
217
-
218
- ```typescript
219
- interface BackendMetrics {
220
- success: number;
221
- fail: number;
222
- }
223
-
224
- export class MetricsCollector {
225
- private metrics: Record<string, BackendMetrics> = {
226
- nodecrypto: { success: 0, fail: 0 },
227
- webcrypto: { success: 0, fail: 0 },
228
- ie11: { success: 0, fail: 0 },
229
- purejs: { success: 0, fail: 0 }
230
- };
231
-
232
- recordSuccess(backend: string): void {
233
- if (this.metrics[backend]) {
234
- this.metrics[backend].success++;
235
- }
236
- }
237
-
238
- recordFail(backend: string): void {
239
- if (this.metrics[backend]) {
240
- this.metrics[backend].fail++;
241
- }
242
- }
243
-
244
- getMetrics(): Record<string, BackendMetrics> {
245
- return this.metrics;
246
- }
247
-
248
- getSummary(): string {
249
- const total = Object.values(this.metrics).reduce(
250
- (sum, m) => sum + m.success + m.fail,
251
- 0
252
- );
253
-
254
- return `Total operations: ${total}\n` +
255
- Object.entries(this.metrics)
256
- .map(([backend, m]) =>
257
- `${backend}: ${m.success} success, ${m.fail} fail`
258
- )
259
- .join('\n');
260
- }
261
-
262
- reset(): void {
263
- Object.keys(this.metrics).forEach(key => {
264
- this.metrics[key] = { success: 0, fail: 0 };
265
- });
266
- }
267
- }
268
-
269
- export const metrics = new MetricsCollector();
270
- ```
271
-
272
- ### 5. Tests
273
-
274
- Создать файл `__tests__/adapters/fallback.test.ts`:
275
-
276
- ```typescript
277
- describe('FallbackManager', () => {
278
- let manager: FallbackManager;
279
-
280
- beforeAll(() => {
281
- manager = new FallbackManager();
282
- });
283
-
284
- it('should hash with fallback', async () => {
285
- const result = await manager.hash('hello');
286
- expect(result.success).toBe(true);
287
- expect(result.data).toBe('5d41402abc4b2a76b9719d911017c592');
288
- });
289
-
290
- it('should get best backend', async () => {
291
- const best = await manager.getBestBackend();
292
- expect(typeof best).toBe('string');
293
- });
294
-
295
- it('should get available backends', async () => {
296
- const available = await manager.getAvailableBackends();
297
- expect(Array.isArray(available)).toBe(true);
298
- expect(available.length).toBeGreaterThan(0);
299
- });
300
-
301
- it('should execute operation with fallback', async () => {
302
- const result = await manager.execute(async (backend) => backend.hash('test'));
303
- expect(result.success).toBe(true);
304
- });
305
-
306
- describe('Robust hash', () => {
307
- it('should hash with fallback', async () => {
308
- const result = await robustHash('hello');
309
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
310
- });
311
-
312
- it('should hash with force backend', async () => {
313
- const result = await robustHash('hello', { forceBackend: 'purejs' });
314
- expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
315
- });
316
-
317
- it('should throw on all backends failure', async () => {
318
- // This test requires mocking all backends to fail
319
- // In practice, this should never happen
320
- await expect(robustHash('test')).resolves.toBeDefined();
321
- });
322
- });
323
- });
324
- ```
325
-
326
- ## Ожидаемый результат
327
-
328
- - ✅ Fallback mechanism реализован
329
- - ✅ Автоматический retry с другими backend'ами
330
- - ✅ Мониторинг и метрики
331
- - ✅ Робастная функция robustHash
332
- - ✅ Tests проходят успешно
333
- - ✅ Documentation создана