@danielsimonjr/memory-mcp 0.47.1 → 9.8.0

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 (207) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +2000 -194
  3. package/dist/__tests__/file-path.test.js +5 -5
  4. package/dist/__tests__/knowledge-graph.test.js +3 -8
  5. package/dist/core/EntityManager.d.ts +266 -0
  6. package/dist/core/EntityManager.d.ts.map +1 -0
  7. package/dist/core/EntityManager.js +85 -133
  8. package/dist/core/GraphEventEmitter.d.ts +202 -0
  9. package/dist/core/GraphEventEmitter.d.ts.map +1 -0
  10. package/dist/core/GraphEventEmitter.js +346 -0
  11. package/dist/core/GraphStorage.d.ts +395 -0
  12. package/dist/core/GraphStorage.d.ts.map +1 -0
  13. package/dist/core/GraphStorage.js +643 -31
  14. package/dist/core/GraphTraversal.d.ts +141 -0
  15. package/dist/core/GraphTraversal.d.ts.map +1 -0
  16. package/dist/core/GraphTraversal.js +573 -0
  17. package/dist/core/HierarchyManager.d.ts +111 -0
  18. package/dist/core/HierarchyManager.d.ts.map +1 -0
  19. package/dist/{features → core}/HierarchyManager.js +14 -9
  20. package/dist/core/ManagerContext.d.ts +72 -0
  21. package/dist/core/ManagerContext.d.ts.map +1 -0
  22. package/dist/core/ManagerContext.js +118 -0
  23. package/dist/core/ObservationManager.d.ts +85 -0
  24. package/dist/core/ObservationManager.d.ts.map +1 -0
  25. package/dist/core/ObservationManager.js +51 -57
  26. package/dist/core/RelationManager.d.ts +131 -0
  27. package/dist/core/RelationManager.d.ts.map +1 -0
  28. package/dist/core/RelationManager.js +31 -7
  29. package/dist/core/SQLiteStorage.d.ts +354 -0
  30. package/dist/core/SQLiteStorage.d.ts.map +1 -0
  31. package/dist/core/SQLiteStorage.js +917 -0
  32. package/dist/core/StorageFactory.d.ts +45 -0
  33. package/dist/core/StorageFactory.d.ts.map +1 -0
  34. package/dist/core/StorageFactory.js +64 -0
  35. package/dist/core/TransactionManager.d.ts +464 -0
  36. package/dist/core/TransactionManager.d.ts.map +1 -0
  37. package/dist/core/TransactionManager.js +490 -13
  38. package/dist/core/index.d.ts +17 -0
  39. package/dist/core/index.d.ts.map +1 -0
  40. package/dist/core/index.js +12 -2
  41. package/dist/features/AnalyticsManager.d.ts +44 -0
  42. package/dist/features/AnalyticsManager.d.ts.map +1 -0
  43. package/dist/features/AnalyticsManager.js +14 -13
  44. package/dist/features/ArchiveManager.d.ts +133 -0
  45. package/dist/features/ArchiveManager.d.ts.map +1 -0
  46. package/dist/features/ArchiveManager.js +221 -14
  47. package/dist/features/CompressionManager.d.ts +117 -0
  48. package/dist/features/CompressionManager.d.ts.map +1 -0
  49. package/dist/features/CompressionManager.js +189 -20
  50. package/dist/features/IOManager.d.ts +225 -0
  51. package/dist/features/IOManager.d.ts.map +1 -0
  52. package/dist/features/IOManager.js +1041 -0
  53. package/dist/features/StreamingExporter.d.ts +123 -0
  54. package/dist/features/StreamingExporter.d.ts.map +1 -0
  55. package/dist/features/StreamingExporter.js +203 -0
  56. package/dist/features/TagManager.d.ts +147 -0
  57. package/dist/features/TagManager.d.ts.map +1 -0
  58. package/dist/features/index.d.ts +12 -0
  59. package/dist/features/index.d.ts.map +1 -0
  60. package/dist/features/index.js +5 -6
  61. package/dist/index.d.ts +9 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +12 -45
  64. package/dist/memory.jsonl +1 -18
  65. package/dist/search/BasicSearch.d.ts +51 -0
  66. package/dist/search/BasicSearch.d.ts.map +1 -0
  67. package/dist/search/BasicSearch.js +9 -3
  68. package/dist/search/BooleanSearch.d.ts +98 -0
  69. package/dist/search/BooleanSearch.d.ts.map +1 -0
  70. package/dist/search/BooleanSearch.js +156 -9
  71. package/dist/search/EmbeddingService.d.ts +178 -0
  72. package/dist/search/EmbeddingService.d.ts.map +1 -0
  73. package/dist/search/EmbeddingService.js +358 -0
  74. package/dist/search/FuzzySearch.d.ts +118 -0
  75. package/dist/search/FuzzySearch.d.ts.map +1 -0
  76. package/dist/search/FuzzySearch.js +241 -25
  77. package/dist/search/QueryCostEstimator.d.ts +111 -0
  78. package/dist/search/QueryCostEstimator.d.ts.map +1 -0
  79. package/dist/search/QueryCostEstimator.js +355 -0
  80. package/dist/search/RankedSearch.d.ts +71 -0
  81. package/dist/search/RankedSearch.d.ts.map +1 -0
  82. package/dist/search/RankedSearch.js +54 -6
  83. package/dist/search/SavedSearchManager.d.ts +79 -0
  84. package/dist/search/SavedSearchManager.d.ts.map +1 -0
  85. package/dist/search/SearchFilterChain.d.ts +120 -0
  86. package/dist/search/SearchFilterChain.d.ts.map +1 -0
  87. package/dist/search/SearchFilterChain.js +2 -4
  88. package/dist/search/SearchManager.d.ts +326 -0
  89. package/dist/search/SearchManager.d.ts.map +1 -0
  90. package/dist/search/SearchManager.js +148 -0
  91. package/dist/search/SearchSuggestions.d.ts +27 -0
  92. package/dist/search/SearchSuggestions.d.ts.map +1 -0
  93. package/dist/search/SearchSuggestions.js +1 -1
  94. package/dist/search/SemanticSearch.d.ts +149 -0
  95. package/dist/search/SemanticSearch.d.ts.map +1 -0
  96. package/dist/search/SemanticSearch.js +323 -0
  97. package/dist/search/TFIDFEventSync.d.ts +85 -0
  98. package/dist/search/TFIDFEventSync.d.ts.map +1 -0
  99. package/dist/search/TFIDFEventSync.js +133 -0
  100. package/dist/search/TFIDFIndexManager.d.ts +151 -0
  101. package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
  102. package/dist/search/TFIDFIndexManager.js +232 -17
  103. package/dist/search/VectorStore.d.ts +235 -0
  104. package/dist/search/VectorStore.d.ts.map +1 -0
  105. package/dist/search/VectorStore.js +311 -0
  106. package/dist/search/index.d.ts +21 -0
  107. package/dist/search/index.d.ts.map +1 -0
  108. package/dist/search/index.js +12 -0
  109. package/dist/server/MCPServer.d.ts +21 -0
  110. package/dist/server/MCPServer.d.ts.map +1 -0
  111. package/dist/server/MCPServer.js +4 -4
  112. package/dist/server/responseCompressor.d.ts +94 -0
  113. package/dist/server/responseCompressor.d.ts.map +1 -0
  114. package/dist/server/responseCompressor.js +127 -0
  115. package/dist/server/toolDefinitions.d.ts +27 -0
  116. package/dist/server/toolDefinitions.d.ts.map +1 -0
  117. package/dist/server/toolDefinitions.js +189 -18
  118. package/dist/server/toolHandlers.d.ts +41 -0
  119. package/dist/server/toolHandlers.d.ts.map +1 -0
  120. package/dist/server/toolHandlers.js +467 -75
  121. package/dist/types/index.d.ts +13 -0
  122. package/dist/types/index.d.ts.map +1 -0
  123. package/dist/types/index.js +1 -1
  124. package/dist/types/types.d.ts +1654 -0
  125. package/dist/types/types.d.ts.map +1 -0
  126. package/dist/types/types.js +9 -0
  127. package/dist/utils/compressedCache.d.ts +192 -0
  128. package/dist/utils/compressedCache.d.ts.map +1 -0
  129. package/dist/utils/compressedCache.js +309 -0
  130. package/dist/utils/compressionUtil.d.ts +214 -0
  131. package/dist/utils/compressionUtil.d.ts.map +1 -0
  132. package/dist/utils/compressionUtil.js +247 -0
  133. package/dist/utils/constants.d.ts +245 -0
  134. package/dist/utils/constants.d.ts.map +1 -0
  135. package/dist/utils/constants.js +124 -0
  136. package/dist/utils/entityUtils.d.ts +321 -0
  137. package/dist/utils/entityUtils.d.ts.map +1 -0
  138. package/dist/utils/entityUtils.js +434 -4
  139. package/dist/utils/errors.d.ts +95 -0
  140. package/dist/utils/errors.d.ts.map +1 -0
  141. package/dist/utils/errors.js +24 -0
  142. package/dist/utils/formatters.d.ts +145 -0
  143. package/dist/utils/formatters.d.ts.map +1 -0
  144. package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
  145. package/dist/utils/index.d.ts +23 -0
  146. package/dist/utils/index.d.ts.map +1 -0
  147. package/dist/utils/index.js +69 -31
  148. package/dist/utils/indexes.d.ts +270 -0
  149. package/dist/utils/indexes.d.ts.map +1 -0
  150. package/dist/utils/indexes.js +526 -0
  151. package/dist/utils/logger.d.ts +24 -0
  152. package/dist/utils/logger.d.ts.map +1 -0
  153. package/dist/utils/operationUtils.d.ts +124 -0
  154. package/dist/utils/operationUtils.d.ts.map +1 -0
  155. package/dist/utils/operationUtils.js +175 -0
  156. package/dist/utils/parallelUtils.d.ts +72 -0
  157. package/dist/utils/parallelUtils.d.ts.map +1 -0
  158. package/dist/utils/parallelUtils.js +169 -0
  159. package/dist/utils/schemas.d.ts +374 -0
  160. package/dist/utils/schemas.d.ts.map +1 -0
  161. package/dist/utils/schemas.js +302 -2
  162. package/dist/utils/searchAlgorithms.d.ts +99 -0
  163. package/dist/utils/searchAlgorithms.d.ts.map +1 -0
  164. package/dist/utils/searchAlgorithms.js +167 -0
  165. package/dist/utils/searchCache.d.ts +108 -0
  166. package/dist/utils/searchCache.d.ts.map +1 -0
  167. package/dist/utils/taskScheduler.d.ts +290 -0
  168. package/dist/utils/taskScheduler.d.ts.map +1 -0
  169. package/dist/utils/taskScheduler.js +466 -0
  170. package/dist/workers/index.d.ts +12 -0
  171. package/dist/workers/index.d.ts.map +1 -0
  172. package/dist/workers/index.js +9 -0
  173. package/dist/workers/levenshteinWorker.d.ts +60 -0
  174. package/dist/workers/levenshteinWorker.d.ts.map +1 -0
  175. package/dist/workers/levenshteinWorker.js +98 -0
  176. package/package.json +17 -4
  177. package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
  178. package/dist/__tests__/integration/workflows.test.js +0 -449
  179. package/dist/__tests__/performance/benchmarks.test.js +0 -413
  180. package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
  181. package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
  182. package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
  183. package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
  184. package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
  185. package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
  186. package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
  187. package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
  188. package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
  189. package/dist/core/KnowledgeGraphManager.js +0 -423
  190. package/dist/features/BackupManager.js +0 -311
  191. package/dist/features/ExportManager.js +0 -305
  192. package/dist/features/ImportExportManager.js +0 -50
  193. package/dist/features/ImportManager.js +0 -328
  194. package/dist/types/analytics.types.js +0 -6
  195. package/dist/types/entity.types.js +0 -7
  196. package/dist/types/import-export.types.js +0 -7
  197. package/dist/types/search.types.js +0 -7
  198. package/dist/types/tag.types.js +0 -6
  199. package/dist/utils/dateUtils.js +0 -89
  200. package/dist/utils/filterUtils.js +0 -155
  201. package/dist/utils/levenshtein.js +0 -62
  202. package/dist/utils/pathUtils.js +0 -115
  203. package/dist/utils/responseFormatter.js +0 -55
  204. package/dist/utils/tagUtils.js +0 -107
  205. package/dist/utils/tfidf.js +0 -90
  206. package/dist/utils/validationHelper.js +0 -99
  207. package/dist/utils/validationUtils.js +0 -109
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Operation Utilities
3
+ *
4
+ * Phase 9B: Utilities for long-running operations with progress tracking
5
+ * and cancellation support.
6
+ *
7
+ * @module utils/operationUtils
8
+ */
9
+ import { OperationCancelledError } from './errors.js';
10
+ /**
11
+ * Check if an operation has been cancelled via AbortSignal.
12
+ * Throws OperationCancelledError if the signal is aborted.
13
+ *
14
+ * @param signal - Optional AbortSignal to check
15
+ * @param operation - Optional operation name for error message
16
+ * @throws OperationCancelledError if signal is aborted
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * for (const item of items) {
21
+ * checkCancellation(options?.signal, 'batch processing');
22
+ * await processItem(item);
23
+ * }
24
+ * ```
25
+ */
26
+ export function checkCancellation(signal, operation) {
27
+ if (signal?.aborted) {
28
+ throw new OperationCancelledError(operation);
29
+ }
30
+ }
31
+ /**
32
+ * Create a throttled progress reporter to avoid excessive callback invocations.
33
+ * Returns undefined if no callback is provided.
34
+ *
35
+ * @param callback - Optional progress callback to throttle
36
+ * @param throttleMs - Minimum time between callbacks (default: 100ms)
37
+ * @returns Throttled callback or undefined
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const reportProgress = createProgressReporter(options?.onProgress, 50);
42
+ * for (let i = 0; i < total; i++) {
43
+ * reportProgress?.({ completed: i, total, percentage: (i / total) * 100 });
44
+ * }
45
+ * ```
46
+ */
47
+ export function createProgressReporter(callback, throttleMs = 100) {
48
+ if (!callback)
49
+ return undefined;
50
+ let lastCallTime = 0;
51
+ return (progress) => {
52
+ const now = Date.now();
53
+ // Always report 0% and 100%
54
+ if (progress.percentage === 0 || progress.percentage >= 100 || now - lastCallTime >= throttleMs) {
55
+ lastCallTime = now;
56
+ callback(progress);
57
+ }
58
+ };
59
+ }
60
+ /**
61
+ * Create a progress object for reporting.
62
+ *
63
+ * @param completed - Number of completed items
64
+ * @param total - Total number of items
65
+ * @param currentTaskId - Optional current task identifier
66
+ * @returns Progress object suitable for ProgressCallback
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * reportProgress?.(createProgress(50, 100, 'processing entities'));
71
+ * // { completed: 50, total: 100, percentage: 50, currentTaskId: 'processing entities' }
72
+ * ```
73
+ */
74
+ export function createProgress(completed, total, currentTaskId) {
75
+ return {
76
+ completed,
77
+ total,
78
+ percentage: total > 0 ? Math.round((completed / total) * 100) : 0,
79
+ currentTaskId,
80
+ };
81
+ }
82
+ /**
83
+ * Execute an operation with multiple distinct phases.
84
+ * Useful when an operation has multiple distinct phases with different weights.
85
+ *
86
+ * @param phases - Array of phase definitions with weight and executor
87
+ * @param onProgress - Optional progress callback
88
+ * @param signal - Optional abort signal
89
+ * @returns Array of results from each phase
90
+ * @throws OperationCancelledError if cancelled during any phase
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const [parseResult, processResult, saveResult] = await executeWithPhases([
95
+ * { name: 'parsing', weight: 20, execute: () => parseData() },
96
+ * { name: 'processing', weight: 60, execute: () => processEntities() },
97
+ * { name: 'saving', weight: 20, execute: () => saveResults() },
98
+ * ], options?.onProgress, options?.signal);
99
+ * ```
100
+ */
101
+ export async function executeWithPhases(phases, onProgress, signal) {
102
+ const totalWeight = phases.reduce((sum, p) => sum + p.weight, 0);
103
+ let completedWeight = 0;
104
+ const results = [];
105
+ for (const phase of phases) {
106
+ checkCancellation(signal, phase.name);
107
+ const phaseStartWeight = completedWeight;
108
+ const phaseProgress = (phasePct) => {
109
+ if (onProgress) {
110
+ const overallPct = ((phaseStartWeight + (phase.weight * phasePct / 100)) / totalWeight) * 100;
111
+ onProgress({
112
+ completed: Math.round(overallPct),
113
+ total: 100,
114
+ percentage: Math.round(overallPct),
115
+ currentTaskId: phase.name,
116
+ });
117
+ }
118
+ };
119
+ const result = await phase.execute(phaseProgress);
120
+ results.push(result);
121
+ completedWeight += phase.weight;
122
+ }
123
+ // Report 100% completion
124
+ onProgress?.({
125
+ completed: 100,
126
+ total: 100,
127
+ percentage: 100,
128
+ });
129
+ return results;
130
+ }
131
+ /**
132
+ * Execute an operation in batches with progress tracking and cancellation support.
133
+ *
134
+ * @param items - Array of items to process
135
+ * @param batchSize - Size of each batch
136
+ * @param processBatch - Function to process each batch
137
+ * @param onProgress - Optional progress callback
138
+ * @param signal - Optional abort signal
139
+ * @param operationName - Optional operation name for cancellation error
140
+ * @returns Array of results from all batches
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * const results = await processBatchesWithProgress(
145
+ * entities,
146
+ * 100,
147
+ * async (batch) => {
148
+ * for (const entity of batch) {
149
+ * await saveEntity(entity);
150
+ * }
151
+ * return batch.length;
152
+ * },
153
+ * options?.onProgress,
154
+ * options?.signal,
155
+ * 'createEntities'
156
+ * );
157
+ * ```
158
+ */
159
+ export async function processBatchesWithProgress(items, batchSize, processBatch, onProgress, signal, operationName) {
160
+ const results = [];
161
+ const total = items.length;
162
+ let processed = 0;
163
+ const reportProgress = createProgressReporter(onProgress);
164
+ reportProgress?.(createProgress(0, total, operationName));
165
+ for (let i = 0; i < items.length; i += batchSize) {
166
+ checkCancellation(signal, operationName);
167
+ const batch = items.slice(i, i + batchSize);
168
+ const result = await processBatch(batch, Math.floor(i / batchSize));
169
+ results.push(result);
170
+ processed += batch.length;
171
+ reportProgress?.(createProgress(processed, total, operationName));
172
+ }
173
+ reportProgress?.(createProgress(total, total, operationName));
174
+ return results;
175
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Parallel Utilities
3
+ *
4
+ * Utilities for parallel array operations using workerpool.
5
+ * Phase 8 Sprint 3: Parallel array operations for improved performance.
6
+ *
7
+ * @module utils/parallelUtils
8
+ */
9
+ import workerpool from '@danielsimonjr/workerpool';
10
+ /**
11
+ * Shutdown the shared worker pool and clean up resources.
12
+ * Should be called when parallel utilities are no longer needed.
13
+ */
14
+ export declare function shutdownParallelUtils(): Promise<void>;
15
+ /**
16
+ * Map items in parallel using workerpool.
17
+ *
18
+ * Splits the array into chunks and processes each chunk in a worker thread.
19
+ * Falls back to single-threaded for small arrays (< MIN_PARALLEL_SIZE).
20
+ *
21
+ * **Note:** The mapping function must be serializable (no closures, external variables).
22
+ * Due to ESM/worker thread compatibility issues, this may fall back to single-threaded
23
+ * execution in some environments (e.g., vitest test runner).
24
+ *
25
+ * @template T - Input item type
26
+ * @template R - Output item type
27
+ * @param items - Array of items to map
28
+ * @param fn - Mapping function (must be serializable)
29
+ * @param chunkSize - Optional chunk size (default: DEFAULT_CHUNK_SIZE)
30
+ * @returns Promise resolving to array of mapped results
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * // Map numbers to their squares
35
+ * const numbers = [1, 2, 3, 4, 5];
36
+ * const squared = await parallelMap(numbers, (n: number) => n * n);
37
+ * // Result: [1, 4, 9, 16, 25]
38
+ * ```
39
+ */
40
+ export declare function parallelMap<T, R>(items: T[], fn: (item: T) => R, chunkSize?: number): Promise<R[]>;
41
+ /**
42
+ * Filter items in parallel using workerpool.
43
+ *
44
+ * Splits the array into chunks and processes each chunk in a worker thread.
45
+ * Falls back to single-threaded for small arrays (< MIN_PARALLEL_SIZE).
46
+ *
47
+ * **Note:** The predicate function must be serializable (no closures, external variables).
48
+ * Due to ESM/worker thread compatibility issues, this may fall back to single-threaded
49
+ * execution in some environments (e.g., vitest test runner).
50
+ *
51
+ * @template T - Item type
52
+ * @param items - Array of items to filter
53
+ * @param predicate - Filter predicate (must be serializable)
54
+ * @param chunkSize - Optional chunk size (default: DEFAULT_CHUNK_SIZE)
55
+ * @returns Promise resolving to filtered array
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Filter even numbers
60
+ * const numbers = [1, 2, 3, 4, 5, 6];
61
+ * const evens = await parallelFilter(numbers, (n: number) => n % 2 === 0);
62
+ * // Result: [2, 4, 6]
63
+ * ```
64
+ */
65
+ export declare function parallelFilter<T>(items: T[], predicate: (item: T) => boolean, chunkSize?: number): Promise<T[]>;
66
+ /**
67
+ * Get statistics about the worker pool.
68
+ *
69
+ * @returns Pool statistics or null if pool is not initialized
70
+ */
71
+ export declare function getPoolStats(): workerpool.PoolStats | null;
72
+ //# sourceMappingURL=parallelUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallelUtils.d.ts","sourceRoot":"","sources":["../../src/utils/parallelUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,UAAU,MAAM,2BAA2B,CAAC;AAoCnD;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,CAAC,EACpC,KAAK,EAAE,CAAC,EAAE,EACV,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAClB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAwCd;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,KAAK,EAAE,CAAC,EAAE,EACV,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,EAC/B,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,CAAC,EAAE,CAAC,CAwCd;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,UAAU,CAAC,SAAS,GAAG,IAAI,CAK1D"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Parallel Utilities
3
+ *
4
+ * Utilities for parallel array operations using workerpool.
5
+ * Phase 8 Sprint 3: Parallel array operations for improved performance.
6
+ *
7
+ * @module utils/parallelUtils
8
+ */
9
+ import workerpool from '@danielsimonjr/workerpool';
10
+ /**
11
+ * Default chunk size for parallel operations.
12
+ * Can be overridden per operation.
13
+ */
14
+ const DEFAULT_CHUNK_SIZE = 100;
15
+ /**
16
+ * Minimum array size to activate parallel processing.
17
+ * For smaller arrays, single-threaded is more efficient due to worker overhead.
18
+ */
19
+ const MIN_PARALLEL_SIZE = 200;
20
+ /**
21
+ * Shared worker pool instance for all parallel utilities.
22
+ * Initialized lazily on first use.
23
+ */
24
+ let sharedPool = null;
25
+ /**
26
+ * Get or create the shared worker pool.
27
+ * Uses inline worker execution (no separate worker file needed).
28
+ *
29
+ * @returns Worker pool instance
30
+ */
31
+ function getPool() {
32
+ if (!sharedPool) {
33
+ sharedPool = workerpool.pool({
34
+ maxWorkers: Math.max(1, workerpool.cpus - 1),
35
+ workerType: 'thread',
36
+ });
37
+ }
38
+ return sharedPool;
39
+ }
40
+ /**
41
+ * Shutdown the shared worker pool and clean up resources.
42
+ * Should be called when parallel utilities are no longer needed.
43
+ */
44
+ export async function shutdownParallelUtils() {
45
+ if (sharedPool) {
46
+ await sharedPool.terminate();
47
+ sharedPool = null;
48
+ }
49
+ }
50
+ /**
51
+ * Map items in parallel using workerpool.
52
+ *
53
+ * Splits the array into chunks and processes each chunk in a worker thread.
54
+ * Falls back to single-threaded for small arrays (< MIN_PARALLEL_SIZE).
55
+ *
56
+ * **Note:** The mapping function must be serializable (no closures, external variables).
57
+ * Due to ESM/worker thread compatibility issues, this may fall back to single-threaded
58
+ * execution in some environments (e.g., vitest test runner).
59
+ *
60
+ * @template T - Input item type
61
+ * @template R - Output item type
62
+ * @param items - Array of items to map
63
+ * @param fn - Mapping function (must be serializable)
64
+ * @param chunkSize - Optional chunk size (default: DEFAULT_CHUNK_SIZE)
65
+ * @returns Promise resolving to array of mapped results
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * // Map numbers to their squares
70
+ * const numbers = [1, 2, 3, 4, 5];
71
+ * const squared = await parallelMap(numbers, (n: number) => n * n);
72
+ * // Result: [1, 4, 9, 16, 25]
73
+ * ```
74
+ */
75
+ export async function parallelMap(items, fn, chunkSize = DEFAULT_CHUNK_SIZE) {
76
+ // Fall back to single-threaded for small arrays
77
+ if (items.length < MIN_PARALLEL_SIZE) {
78
+ return items.map(fn);
79
+ }
80
+ try {
81
+ const pool = getPool();
82
+ // Split items into chunks
83
+ const chunks = [];
84
+ for (let i = 0; i < items.length; i += chunkSize) {
85
+ chunks.push(items.slice(i, i + chunkSize));
86
+ }
87
+ // Convert function to string for serialization
88
+ const fnString = fn.toString();
89
+ // Process chunks in parallel using inline function execution
90
+ const results = await Promise.all(chunks.map(chunk => pool.exec((chunkData, fnStr) => {
91
+ // Reconstruct function from string
92
+ // eslint-disable-next-line no-new-func
93
+ const mapFn = new Function('return ' + fnStr)();
94
+ return chunkData.map(mapFn);
95
+ }, [chunk, fnString])));
96
+ // Flatten results
97
+ return results.flat();
98
+ }
99
+ catch (error) {
100
+ // Fall back to single-threaded if worker execution fails
101
+ // (e.g., in test environments with ESM/worker compatibility issues)
102
+ return items.map(fn);
103
+ }
104
+ }
105
+ /**
106
+ * Filter items in parallel using workerpool.
107
+ *
108
+ * Splits the array into chunks and processes each chunk in a worker thread.
109
+ * Falls back to single-threaded for small arrays (< MIN_PARALLEL_SIZE).
110
+ *
111
+ * **Note:** The predicate function must be serializable (no closures, external variables).
112
+ * Due to ESM/worker thread compatibility issues, this may fall back to single-threaded
113
+ * execution in some environments (e.g., vitest test runner).
114
+ *
115
+ * @template T - Item type
116
+ * @param items - Array of items to filter
117
+ * @param predicate - Filter predicate (must be serializable)
118
+ * @param chunkSize - Optional chunk size (default: DEFAULT_CHUNK_SIZE)
119
+ * @returns Promise resolving to filtered array
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Filter even numbers
124
+ * const numbers = [1, 2, 3, 4, 5, 6];
125
+ * const evens = await parallelFilter(numbers, (n: number) => n % 2 === 0);
126
+ * // Result: [2, 4, 6]
127
+ * ```
128
+ */
129
+ export async function parallelFilter(items, predicate, chunkSize = DEFAULT_CHUNK_SIZE) {
130
+ // Fall back to single-threaded for small arrays
131
+ if (items.length < MIN_PARALLEL_SIZE) {
132
+ return items.filter(predicate);
133
+ }
134
+ try {
135
+ const pool = getPool();
136
+ // Split items into chunks
137
+ const chunks = [];
138
+ for (let i = 0; i < items.length; i += chunkSize) {
139
+ chunks.push(items.slice(i, i + chunkSize));
140
+ }
141
+ // Convert function to string for serialization
142
+ const predicateString = predicate.toString();
143
+ // Process chunks in parallel using inline function execution
144
+ const results = await Promise.all(chunks.map(chunk => pool.exec((chunkData, predicateStr) => {
145
+ // Reconstruct function from string
146
+ // eslint-disable-next-line no-new-func
147
+ const filterFn = new Function('return ' + predicateStr)();
148
+ return chunkData.filter(filterFn);
149
+ }, [chunk, predicateString])));
150
+ // Flatten results
151
+ return results.flat();
152
+ }
153
+ catch (error) {
154
+ // Fall back to single-threaded if worker execution fails
155
+ // (e.g., in test environments with ESM/worker compatibility issues)
156
+ return items.filter(predicate);
157
+ }
158
+ }
159
+ /**
160
+ * Get statistics about the worker pool.
161
+ *
162
+ * @returns Pool statistics or null if pool is not initialized
163
+ */
164
+ export function getPoolStats() {
165
+ if (!sharedPool) {
166
+ return null;
167
+ }
168
+ return sharedPool.stats();
169
+ }