pure-md5 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/adapters/ie11.cjs +1 -2
  2. package/dist/adapters/ie11.js +1 -2
  3. package/dist/adapters/node.cjs +1 -2
  4. package/dist/adapters/node.js +1 -2
  5. package/dist/adapters/webcrypto.cjs +1 -2
  6. package/dist/adapters/webcrypto.js +1 -2
  7. package/dist/core/index.cjs +1 -2
  8. package/dist/core/index.js +1 -2
  9. package/dist/index.cjs +1 -2
  10. package/dist/index.js +1 -2
  11. package/dist/stream/adapter.cjs +1 -2
  12. package/dist/stream/adapter.js +1 -2
  13. package/dist/stream/fs-utils.cjs +1 -2
  14. package/dist/stream/fs-utils.js +1 -2
  15. package/dist/stream/index.cjs +1 -2
  16. package/dist/stream/index.js +1 -2
  17. package/dist/stream/light/index.cjs +1 -2
  18. package/dist/stream/light/index.js +1 -2
  19. package/dist/stream/md5-stream.cjs +1 -2
  20. package/dist/stream/md5-stream.js +1 -2
  21. package/dist/stream/whatwg-stream.cjs +1 -2
  22. package/dist/stream/whatwg-stream.js +1 -2
  23. package/dist/utils/detect.cjs +1 -2
  24. package/dist/utils/detect.js +1 -2
  25. package/package.json +1 -1
  26. package/pure-md5-0.2.0.tgz +0 -0
  27. package/.aliases +0 -19
  28. package/.bash_profile +0 -12
  29. package/.bash_prompt +0 -56
  30. package/.changeset/README.md +0 -32
  31. package/.changeset/config.json +0 -16
  32. package/.continue/mcpServers/new-mcp-server.yaml +0 -10
  33. package/.continue/rules +0 -29
  34. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  35. package/.github/ISSUE_TEMPLATE/documentation.md +0 -20
  36. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  37. package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
  38. package/.github/workflows/npm-publish.yml +0 -33
  39. package/.github/workflows/release.yml +0 -42
  40. package/CHANGELOG.md +0 -9
  41. package/CONTRIBUTING.md +0 -203
  42. package/MIGRATION_GUIDE_STREAMS.md +0 -374
  43. package/STREAM_API.md +0 -582
  44. package/STREAM_BENCHMARKS.md +0 -232
  45. package/STREAM_EXAMPLES.md +0 -669
  46. package/STREAM_OPTIMIZATION_REPORT.md +0 -136
  47. package/STREAM_TROUBLESHOOTING.md +0 -537
  48. package/WEB_CRYPTO_TESTS_SUMMARY.md +0 -140
  49. package/WHATWG_STREAMS.md +0 -191
  50. package/__tests__/adapters/node-crypto.test.ts +0 -167
  51. package/__tests__/adapters/web-crypto-node.test.ts +0 -73
  52. package/__tests__/adapters/web-crypto.test.ts +0 -195
  53. package/__tests__/add32.test.ts +0 -33
  54. package/__tests__/fallback.test.ts +0 -345
  55. package/__tests__/hex.test.ts +0 -38
  56. package/__tests__/hex_chr.test.ts +0 -20
  57. package/__tests__/index.test.ts +0 -87
  58. package/__tests__/integration/fixtures/test-file.txt +0 -1
  59. package/__tests__/integration/md5-stream-file.test.ts +0 -293
  60. package/__tests__/integration/node-crypto-file.test.ts +0 -86
  61. package/__tests__/integration/web-crypto.test.ts +0 -38
  62. package/__tests__/md51.test.ts +0 -73
  63. package/__tests__/md5block.test.ts +0 -61
  64. package/__tests__/md5cycle.test.ts +0 -48
  65. package/__tests__/round-functions.test.ts +0 -87
  66. package/__tests__/stream/fs-utils.test.ts +0 -209
  67. package/__tests__/stream/md5-stream-edge-cases.test.ts +0 -461
  68. package/__tests__/stream/md5-stream.test.ts +0 -418
  69. package/__tests__/stream/whatwg-stream.test.ts +0 -355
  70. package/__tests__/stream/whatwg-stream.test.ts.bak2 +0 -335
  71. package/benchmarks/md5-stream.bench.ts +0 -212
  72. package/benchmarks/whatwg-stream.bench.ts +0 -180
  73. package/dist/adapters/ie11.cjs.map +0 -1
  74. package/dist/adapters/ie11.js.map +0 -1
  75. package/dist/adapters/node.cjs.map +0 -1
  76. package/dist/adapters/node.js.map +0 -1
  77. package/dist/adapters/webcrypto.cjs.map +0 -1
  78. package/dist/adapters/webcrypto.js.map +0 -1
  79. package/dist/chunk-2YXXFGBV.js +0 -2
  80. package/dist/chunk-2YXXFGBV.js.map +0 -1
  81. package/dist/chunk-4KSCMS4Q.js +0 -2
  82. package/dist/chunk-4KSCMS4Q.js.map +0 -1
  83. package/dist/chunk-6P2QV5SR.js +0 -4
  84. package/dist/chunk-6P2QV5SR.js.map +0 -1
  85. package/dist/chunk-G5WHEAIQ.js +0 -2
  86. package/dist/chunk-G5WHEAIQ.js.map +0 -1
  87. package/dist/chunk-H2K353LR.js +0 -2
  88. package/dist/chunk-H2K353LR.js.map +0 -1
  89. package/dist/chunk-JKVD5LHZ.js +0 -2
  90. package/dist/chunk-JKVD5LHZ.js.map +0 -1
  91. package/dist/chunk-NWQ4N5RX.js +0 -2
  92. package/dist/chunk-NWQ4N5RX.js.map +0 -1
  93. package/dist/chunk-PHZ7FTYF.js +0 -2
  94. package/dist/chunk-PHZ7FTYF.js.map +0 -1
  95. package/dist/chunk-PNZTVQA7.js +0 -2
  96. package/dist/chunk-PNZTVQA7.js.map +0 -1
  97. package/dist/chunk-R4JB5MBR.js +0 -2
  98. package/dist/chunk-R4JB5MBR.js.map +0 -1
  99. package/dist/chunk-VFOAY6XI.js +0 -2
  100. package/dist/chunk-VFOAY6XI.js.map +0 -1
  101. package/dist/chunk-XB5BQIEX.js +0 -2
  102. package/dist/chunk-XB5BQIEX.js.map +0 -1
  103. package/dist/core/index.cjs.map +0 -1
  104. package/dist/core/index.js.map +0 -1
  105. package/dist/index.cjs.map +0 -1
  106. package/dist/index.js.map +0 -1
  107. package/dist/stream/adapter.cjs.map +0 -1
  108. package/dist/stream/adapter.js.map +0 -1
  109. package/dist/stream/fs-utils.cjs.map +0 -1
  110. package/dist/stream/fs-utils.js.map +0 -1
  111. package/dist/stream/index.cjs.map +0 -1
  112. package/dist/stream/index.js.map +0 -1
  113. package/dist/stream/light/index.cjs.map +0 -1
  114. package/dist/stream/light/index.js.map +0 -1
  115. package/dist/stream/md5-stream.cjs.map +0 -1
  116. package/dist/stream/md5-stream.js.map +0 -1
  117. package/dist/stream/whatwg-stream.cjs.map +0 -1
  118. package/dist/stream/whatwg-stream.js.map +0 -1
  119. package/dist/utils/detect.cjs.map +0 -1
  120. package/dist/utils/detect.js.map +0 -1
  121. package/planning/03-optimization-size-tree-shaking/01-es-modules-tree-shaking.md +0 -152
  122. package/planning/03-optimization-size-tree-shaking/02-consolidate-modules.md +0 -65
  123. package/planning/03-optimization-size-tree-shaking/03-remove-duplicate-add32.md +0 -93
  124. package/planning/03-optimization-size-tree-shaking/04-remove-runtime-check.md +0 -102
  125. package/planning/03-optimization-size-tree-shaking/05-optimize-loops-performance.md +0 -107
  126. package/planning/03-optimization-size-tree-shaking/06-tsup-formats-configuration.md +0 -227
  127. package/planning/03-optimization-size-tree-shaking/07-multiple-build-formats.md +0 -228
  128. package/planning/03-optimization-size-tree-shaking/08-benchmarks-metrics.md +0 -34
  129. package/planning/03-optimization-size-tree-shaking/MIGRATION_GUIDE.md +0 -260
  130. package/planning/03-optimization-size-tree-shaking/README.md +0 -173
  131. package/planning/03-optimization-size-tree-shaking/SUMMARY.md +0 -168
  132. package/planning/04-adapter-backend/03-backend-web-crypto.md +0 -149
  133. package/planning/04-adapter-backend/04-backend-node-crypto.md +0 -181
  134. package/planning/04-adapter-backend/05-backend-pure-js.md +0 -174
  135. package/planning/04-adapter-backend/06-backend-ie11.md +0 -158
  136. package/planning/04-adapter-backend/07-detection-environment.md +0 -232
  137. package/planning/04-adapter-backend/08-detection-backend.md +0 -210
  138. package/planning/04-adapter-backend/09-adapter-unified.md +0 -255
  139. package/planning/04-adapter-backend/10-fallback-mechanism.md +0 -333
  140. package/planning/04-adapter-backend/11-tests-backend-web-crypto.md +0 -191
  141. package/planning/04-adapter-backend/12-tests-backend-node-crypto.md +0 -222
  142. package/planning/04-adapter-backend/README.md +0 -45
  143. package/planning/05-documentation-publishing/01-README-optimization.md +0 -105
  144. package/planning/05-documentation-publishing/02-VitePress-site-evaluation.md +0 -136
  145. package/planning/05-documentation-publishing/03-Changeset-setup.md +0 -192
  146. package/planning/05-documentation-publishing/04-GitHub-templates.md +0 -252
  147. package/planning/05-documentation-publishing/README.md +0 -22
  148. package/planning/05-documentation-publishing/STATUS.md +0 -222
  149. package/planning/prd.md +0 -405
  150. package/planning/streams/01-create-md5stream-class.md +0 -69
  151. package/planning/streams/02-create-factory-api.md +0 -65
  152. package/planning/streams/03-fs-integration.md +0 -37
  153. package/planning/streams/04-whatwg-streams-support.md +0 -37
  154. package/planning/streams/05-audit-optimization.md +0 -121
  155. package/planning/streams/06-comprehensive-tests-docs.md +0 -137
  156. package/planning/streams/07-architecture-integration.md +0 -38
  157. package/planning/streams/README.md +0 -98
  158. 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 создана