@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.
- package/LICENSE +22 -0
- package/README.md +2000 -194
- package/dist/__tests__/file-path.test.js +5 -5
- package/dist/__tests__/knowledge-graph.test.js +3 -8
- package/dist/core/EntityManager.d.ts +266 -0
- package/dist/core/EntityManager.d.ts.map +1 -0
- package/dist/core/EntityManager.js +85 -133
- package/dist/core/GraphEventEmitter.d.ts +202 -0
- package/dist/core/GraphEventEmitter.d.ts.map +1 -0
- package/dist/core/GraphEventEmitter.js +346 -0
- package/dist/core/GraphStorage.d.ts +395 -0
- package/dist/core/GraphStorage.d.ts.map +1 -0
- package/dist/core/GraphStorage.js +643 -31
- package/dist/core/GraphTraversal.d.ts +141 -0
- package/dist/core/GraphTraversal.d.ts.map +1 -0
- package/dist/core/GraphTraversal.js +573 -0
- package/dist/core/HierarchyManager.d.ts +111 -0
- package/dist/core/HierarchyManager.d.ts.map +1 -0
- package/dist/{features → core}/HierarchyManager.js +14 -9
- package/dist/core/ManagerContext.d.ts +72 -0
- package/dist/core/ManagerContext.d.ts.map +1 -0
- package/dist/core/ManagerContext.js +118 -0
- package/dist/core/ObservationManager.d.ts +85 -0
- package/dist/core/ObservationManager.d.ts.map +1 -0
- package/dist/core/ObservationManager.js +51 -57
- package/dist/core/RelationManager.d.ts +131 -0
- package/dist/core/RelationManager.d.ts.map +1 -0
- package/dist/core/RelationManager.js +31 -7
- package/dist/core/SQLiteStorage.d.ts +354 -0
- package/dist/core/SQLiteStorage.d.ts.map +1 -0
- package/dist/core/SQLiteStorage.js +917 -0
- package/dist/core/StorageFactory.d.ts +45 -0
- package/dist/core/StorageFactory.d.ts.map +1 -0
- package/dist/core/StorageFactory.js +64 -0
- package/dist/core/TransactionManager.d.ts +464 -0
- package/dist/core/TransactionManager.d.ts.map +1 -0
- package/dist/core/TransactionManager.js +490 -13
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +12 -2
- package/dist/features/AnalyticsManager.d.ts +44 -0
- package/dist/features/AnalyticsManager.d.ts.map +1 -0
- package/dist/features/AnalyticsManager.js +14 -13
- package/dist/features/ArchiveManager.d.ts +133 -0
- package/dist/features/ArchiveManager.d.ts.map +1 -0
- package/dist/features/ArchiveManager.js +221 -14
- package/dist/features/CompressionManager.d.ts +117 -0
- package/dist/features/CompressionManager.d.ts.map +1 -0
- package/dist/features/CompressionManager.js +189 -20
- package/dist/features/IOManager.d.ts +225 -0
- package/dist/features/IOManager.d.ts.map +1 -0
- package/dist/features/IOManager.js +1041 -0
- package/dist/features/StreamingExporter.d.ts +123 -0
- package/dist/features/StreamingExporter.d.ts.map +1 -0
- package/dist/features/StreamingExporter.js +203 -0
- package/dist/features/TagManager.d.ts +147 -0
- package/dist/features/TagManager.d.ts.map +1 -0
- package/dist/features/index.d.ts +12 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +5 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -45
- package/dist/memory.jsonl +1 -18
- package/dist/search/BasicSearch.d.ts +51 -0
- package/dist/search/BasicSearch.d.ts.map +1 -0
- package/dist/search/BasicSearch.js +9 -3
- package/dist/search/BooleanSearch.d.ts +98 -0
- package/dist/search/BooleanSearch.d.ts.map +1 -0
- package/dist/search/BooleanSearch.js +156 -9
- package/dist/search/EmbeddingService.d.ts +178 -0
- package/dist/search/EmbeddingService.d.ts.map +1 -0
- package/dist/search/EmbeddingService.js +358 -0
- package/dist/search/FuzzySearch.d.ts +118 -0
- package/dist/search/FuzzySearch.d.ts.map +1 -0
- package/dist/search/FuzzySearch.js +241 -25
- package/dist/search/QueryCostEstimator.d.ts +111 -0
- package/dist/search/QueryCostEstimator.d.ts.map +1 -0
- package/dist/search/QueryCostEstimator.js +355 -0
- package/dist/search/RankedSearch.d.ts +71 -0
- package/dist/search/RankedSearch.d.ts.map +1 -0
- package/dist/search/RankedSearch.js +54 -6
- package/dist/search/SavedSearchManager.d.ts +79 -0
- package/dist/search/SavedSearchManager.d.ts.map +1 -0
- package/dist/search/SearchFilterChain.d.ts +120 -0
- package/dist/search/SearchFilterChain.d.ts.map +1 -0
- package/dist/search/SearchFilterChain.js +2 -4
- package/dist/search/SearchManager.d.ts +326 -0
- package/dist/search/SearchManager.d.ts.map +1 -0
- package/dist/search/SearchManager.js +148 -0
- package/dist/search/SearchSuggestions.d.ts +27 -0
- package/dist/search/SearchSuggestions.d.ts.map +1 -0
- package/dist/search/SearchSuggestions.js +1 -1
- package/dist/search/SemanticSearch.d.ts +149 -0
- package/dist/search/SemanticSearch.d.ts.map +1 -0
- package/dist/search/SemanticSearch.js +323 -0
- package/dist/search/TFIDFEventSync.d.ts +85 -0
- package/dist/search/TFIDFEventSync.d.ts.map +1 -0
- package/dist/search/TFIDFEventSync.js +133 -0
- package/dist/search/TFIDFIndexManager.d.ts +151 -0
- package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
- package/dist/search/TFIDFIndexManager.js +232 -17
- package/dist/search/VectorStore.d.ts +235 -0
- package/dist/search/VectorStore.d.ts.map +1 -0
- package/dist/search/VectorStore.js +311 -0
- package/dist/search/index.d.ts +21 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +12 -0
- package/dist/server/MCPServer.d.ts +21 -0
- package/dist/server/MCPServer.d.ts.map +1 -0
- package/dist/server/MCPServer.js +4 -4
- package/dist/server/responseCompressor.d.ts +94 -0
- package/dist/server/responseCompressor.d.ts.map +1 -0
- package/dist/server/responseCompressor.js +127 -0
- package/dist/server/toolDefinitions.d.ts +27 -0
- package/dist/server/toolDefinitions.d.ts.map +1 -0
- package/dist/server/toolDefinitions.js +189 -18
- package/dist/server/toolHandlers.d.ts +41 -0
- package/dist/server/toolHandlers.d.ts.map +1 -0
- package/dist/server/toolHandlers.js +467 -75
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -1
- package/dist/types/types.d.ts +1654 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +9 -0
- package/dist/utils/compressedCache.d.ts +192 -0
- package/dist/utils/compressedCache.d.ts.map +1 -0
- package/dist/utils/compressedCache.js +309 -0
- package/dist/utils/compressionUtil.d.ts +214 -0
- package/dist/utils/compressionUtil.d.ts.map +1 -0
- package/dist/utils/compressionUtil.js +247 -0
- package/dist/utils/constants.d.ts +245 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +124 -0
- package/dist/utils/entityUtils.d.ts +321 -0
- package/dist/utils/entityUtils.d.ts.map +1 -0
- package/dist/utils/entityUtils.js +434 -4
- package/dist/utils/errors.d.ts +95 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +24 -0
- package/dist/utils/formatters.d.ts +145 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +69 -31
- package/dist/utils/indexes.d.ts +270 -0
- package/dist/utils/indexes.d.ts.map +1 -0
- package/dist/utils/indexes.js +526 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/operationUtils.d.ts +124 -0
- package/dist/utils/operationUtils.d.ts.map +1 -0
- package/dist/utils/operationUtils.js +175 -0
- package/dist/utils/parallelUtils.d.ts +72 -0
- package/dist/utils/parallelUtils.d.ts.map +1 -0
- package/dist/utils/parallelUtils.js +169 -0
- package/dist/utils/schemas.d.ts +374 -0
- package/dist/utils/schemas.d.ts.map +1 -0
- package/dist/utils/schemas.js +302 -2
- package/dist/utils/searchAlgorithms.d.ts +99 -0
- package/dist/utils/searchAlgorithms.d.ts.map +1 -0
- package/dist/utils/searchAlgorithms.js +167 -0
- package/dist/utils/searchCache.d.ts +108 -0
- package/dist/utils/searchCache.d.ts.map +1 -0
- package/dist/utils/taskScheduler.d.ts +290 -0
- package/dist/utils/taskScheduler.d.ts.map +1 -0
- package/dist/utils/taskScheduler.js +466 -0
- package/dist/workers/index.d.ts +12 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +9 -0
- package/dist/workers/levenshteinWorker.d.ts +60 -0
- package/dist/workers/levenshteinWorker.d.ts.map +1 -0
- package/dist/workers/levenshteinWorker.js +98 -0
- package/package.json +17 -4
- package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
- package/dist/__tests__/integration/workflows.test.js +0 -449
- package/dist/__tests__/performance/benchmarks.test.js +0 -413
- package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
- package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
- package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
- package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
- package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
- package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
- package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
- package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
- package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
- package/dist/core/KnowledgeGraphManager.js +0 -423
- package/dist/features/BackupManager.js +0 -311
- package/dist/features/ExportManager.js +0 -305
- package/dist/features/ImportExportManager.js +0 -50
- package/dist/features/ImportManager.js +0 -328
- package/dist/types/analytics.types.js +0 -6
- package/dist/types/entity.types.js +0 -7
- package/dist/types/import-export.types.js +0 -7
- package/dist/types/search.types.js +0 -7
- package/dist/types/tag.types.js +0 -6
- package/dist/utils/dateUtils.js +0 -89
- package/dist/utils/filterUtils.js +0 -155
- package/dist/utils/levenshtein.js +0 -62
- package/dist/utils/pathUtils.js +0 -115
- package/dist/utils/responseFormatter.js +0 -55
- package/dist/utils/tagUtils.js +0 -107
- package/dist/utils/tfidf.js +0 -90
- package/dist/utils/validationHelper.js +0 -99
- 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
|
+
}
|