rag-lite-ts 1.0.2 → 2.0.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 (208) hide show
  1. package/README.md +605 -93
  2. package/dist/cli/indexer.js +192 -4
  3. package/dist/cli/search.js +50 -11
  4. package/dist/cli.js +183 -26
  5. package/dist/core/abstract-embedder.d.ts +125 -0
  6. package/dist/core/abstract-embedder.js +264 -0
  7. package/dist/core/actionable-error-messages.d.ts +60 -0
  8. package/dist/core/actionable-error-messages.js +397 -0
  9. package/dist/core/batch-processing-optimizer.d.ts +155 -0
  10. package/dist/core/batch-processing-optimizer.js +541 -0
  11. package/dist/core/binary-index-format.d.ts +52 -0
  12. package/dist/core/binary-index-format.js +122 -0
  13. package/dist/core/chunker.d.ts +2 -0
  14. package/dist/core/cli-database-utils.d.ts +53 -0
  15. package/dist/core/cli-database-utils.js +239 -0
  16. package/dist/core/config.js +10 -3
  17. package/dist/core/content-errors.d.ts +111 -0
  18. package/dist/core/content-errors.js +362 -0
  19. package/dist/core/content-manager.d.ts +343 -0
  20. package/dist/core/content-manager.js +1504 -0
  21. package/dist/core/content-performance-optimizer.d.ts +150 -0
  22. package/dist/core/content-performance-optimizer.js +516 -0
  23. package/dist/core/content-resolver.d.ts +104 -0
  24. package/dist/core/content-resolver.js +285 -0
  25. package/dist/core/cross-modal-search.d.ts +164 -0
  26. package/dist/core/cross-modal-search.js +342 -0
  27. package/dist/core/database-connection-manager.d.ts +109 -0
  28. package/dist/core/database-connection-manager.js +304 -0
  29. package/dist/core/db.d.ts +141 -2
  30. package/dist/core/db.js +631 -89
  31. package/dist/core/embedder-factory.d.ts +176 -0
  32. package/dist/core/embedder-factory.js +338 -0
  33. package/dist/core/index.d.ts +3 -1
  34. package/dist/core/index.js +4 -1
  35. package/dist/core/ingestion.d.ts +85 -15
  36. package/dist/core/ingestion.js +510 -45
  37. package/dist/core/lazy-dependency-loader.d.ts +152 -0
  38. package/dist/core/lazy-dependency-loader.js +453 -0
  39. package/dist/core/mode-detection-service.d.ts +150 -0
  40. package/dist/core/mode-detection-service.js +565 -0
  41. package/dist/core/mode-model-validator.d.ts +92 -0
  42. package/dist/core/mode-model-validator.js +203 -0
  43. package/dist/core/model-registry.d.ts +120 -0
  44. package/dist/core/model-registry.js +415 -0
  45. package/dist/core/model-validator.d.ts +217 -0
  46. package/dist/core/model-validator.js +782 -0
  47. package/dist/core/polymorphic-search-factory.d.ts +154 -0
  48. package/dist/core/polymorphic-search-factory.js +344 -0
  49. package/dist/core/raglite-paths.d.ts +121 -0
  50. package/dist/core/raglite-paths.js +145 -0
  51. package/dist/core/reranking-config.d.ts +42 -0
  52. package/dist/core/reranking-config.js +156 -0
  53. package/dist/core/reranking-factory.d.ts +92 -0
  54. package/dist/core/reranking-factory.js +591 -0
  55. package/dist/core/reranking-strategies.d.ts +325 -0
  56. package/dist/core/reranking-strategies.js +720 -0
  57. package/dist/core/resource-cleanup.d.ts +163 -0
  58. package/dist/core/resource-cleanup.js +371 -0
  59. package/dist/core/resource-manager.d.ts +212 -0
  60. package/dist/core/resource-manager.js +564 -0
  61. package/dist/core/search.d.ts +28 -1
  62. package/dist/core/search.js +83 -5
  63. package/dist/core/streaming-operations.d.ts +145 -0
  64. package/dist/core/streaming-operations.js +409 -0
  65. package/dist/core/types.d.ts +3 -0
  66. package/dist/core/universal-embedder.d.ts +177 -0
  67. package/dist/core/universal-embedder.js +139 -0
  68. package/dist/core/validation-messages.d.ts +99 -0
  69. package/dist/core/validation-messages.js +334 -0
  70. package/dist/core/vector-index.d.ts +1 -1
  71. package/dist/core/vector-index.js +37 -39
  72. package/dist/factories/index.d.ts +3 -1
  73. package/dist/factories/index.js +2 -0
  74. package/dist/factories/polymorphic-factory.d.ts +50 -0
  75. package/dist/factories/polymorphic-factory.js +159 -0
  76. package/dist/factories/text-factory.d.ts +128 -34
  77. package/dist/factories/text-factory.js +346 -97
  78. package/dist/file-processor.d.ts +88 -2
  79. package/dist/file-processor.js +720 -17
  80. package/dist/index.d.ts +32 -0
  81. package/dist/index.js +29 -0
  82. package/dist/ingestion.d.ts +16 -0
  83. package/dist/ingestion.js +21 -0
  84. package/dist/mcp-server.d.ts +35 -3
  85. package/dist/mcp-server.js +1107 -31
  86. package/dist/multimodal/clip-embedder.d.ts +327 -0
  87. package/dist/multimodal/clip-embedder.js +992 -0
  88. package/dist/multimodal/index.d.ts +6 -0
  89. package/dist/multimodal/index.js +6 -0
  90. package/dist/run-error-recovery-tests.d.ts +7 -0
  91. package/dist/run-error-recovery-tests.js +101 -0
  92. package/dist/search.d.ts +60 -9
  93. package/dist/search.js +82 -11
  94. package/dist/test-utils.d.ts +8 -26
  95. package/dist/text/chunker.d.ts +1 -0
  96. package/dist/text/embedder.js +15 -8
  97. package/dist/text/index.d.ts +1 -0
  98. package/dist/text/index.js +1 -0
  99. package/dist/text/reranker.d.ts +1 -2
  100. package/dist/text/reranker.js +17 -47
  101. package/dist/text/sentence-transformer-embedder.d.ts +96 -0
  102. package/dist/text/sentence-transformer-embedder.js +340 -0
  103. package/dist/types.d.ts +39 -0
  104. package/dist/utils/vector-math.d.ts +31 -0
  105. package/dist/utils/vector-math.js +70 -0
  106. package/package.json +27 -6
  107. package/dist/api-errors.d.ts.map +0 -1
  108. package/dist/api-errors.js.map +0 -1
  109. package/dist/cli/indexer.d.ts.map +0 -1
  110. package/dist/cli/indexer.js.map +0 -1
  111. package/dist/cli/search.d.ts.map +0 -1
  112. package/dist/cli/search.js.map +0 -1
  113. package/dist/cli.d.ts.map +0 -1
  114. package/dist/cli.js.map +0 -1
  115. package/dist/config.d.ts.map +0 -1
  116. package/dist/config.js.map +0 -1
  117. package/dist/core/adapters.d.ts.map +0 -1
  118. package/dist/core/adapters.js.map +0 -1
  119. package/dist/core/chunker.d.ts.map +0 -1
  120. package/dist/core/chunker.js.map +0 -1
  121. package/dist/core/config.d.ts.map +0 -1
  122. package/dist/core/config.js.map +0 -1
  123. package/dist/core/db.d.ts.map +0 -1
  124. package/dist/core/db.js.map +0 -1
  125. package/dist/core/error-handler.d.ts.map +0 -1
  126. package/dist/core/error-handler.js.map +0 -1
  127. package/dist/core/index.d.ts.map +0 -1
  128. package/dist/core/index.js.map +0 -1
  129. package/dist/core/ingestion.d.ts.map +0 -1
  130. package/dist/core/ingestion.js.map +0 -1
  131. package/dist/core/interfaces.d.ts.map +0 -1
  132. package/dist/core/interfaces.js.map +0 -1
  133. package/dist/core/path-manager.d.ts.map +0 -1
  134. package/dist/core/path-manager.js.map +0 -1
  135. package/dist/core/search-example.d.ts +0 -25
  136. package/dist/core/search-example.d.ts.map +0 -1
  137. package/dist/core/search-example.js +0 -138
  138. package/dist/core/search-example.js.map +0 -1
  139. package/dist/core/search-pipeline-example.d.ts +0 -21
  140. package/dist/core/search-pipeline-example.d.ts.map +0 -1
  141. package/dist/core/search-pipeline-example.js +0 -188
  142. package/dist/core/search-pipeline-example.js.map +0 -1
  143. package/dist/core/search-pipeline.d.ts.map +0 -1
  144. package/dist/core/search-pipeline.js.map +0 -1
  145. package/dist/core/search.d.ts.map +0 -1
  146. package/dist/core/search.js.map +0 -1
  147. package/dist/core/types.d.ts.map +0 -1
  148. package/dist/core/types.js.map +0 -1
  149. package/dist/core/vector-index.d.ts.map +0 -1
  150. package/dist/core/vector-index.js.map +0 -1
  151. package/dist/dom-polyfills.d.ts.map +0 -1
  152. package/dist/dom-polyfills.js.map +0 -1
  153. package/dist/examples/clean-api-examples.d.ts +0 -44
  154. package/dist/examples/clean-api-examples.d.ts.map +0 -1
  155. package/dist/examples/clean-api-examples.js +0 -206
  156. package/dist/examples/clean-api-examples.js.map +0 -1
  157. package/dist/factories/index.d.ts.map +0 -1
  158. package/dist/factories/index.js.map +0 -1
  159. package/dist/factories/text-factory.d.ts.map +0 -1
  160. package/dist/factories/text-factory.js.map +0 -1
  161. package/dist/file-processor.d.ts.map +0 -1
  162. package/dist/file-processor.js.map +0 -1
  163. package/dist/index-manager.d.ts.map +0 -1
  164. package/dist/index-manager.js.map +0 -1
  165. package/dist/index.d.ts.map +0 -1
  166. package/dist/index.js.map +0 -1
  167. package/dist/indexer.d.ts.map +0 -1
  168. package/dist/indexer.js.map +0 -1
  169. package/dist/ingestion.d.ts.map +0 -1
  170. package/dist/ingestion.js.map +0 -1
  171. package/dist/mcp-server.d.ts.map +0 -1
  172. package/dist/mcp-server.js.map +0 -1
  173. package/dist/preprocess.d.ts.map +0 -1
  174. package/dist/preprocess.js.map +0 -1
  175. package/dist/preprocessors/index.d.ts.map +0 -1
  176. package/dist/preprocessors/index.js.map +0 -1
  177. package/dist/preprocessors/mdx.d.ts.map +0 -1
  178. package/dist/preprocessors/mdx.js.map +0 -1
  179. package/dist/preprocessors/mermaid.d.ts.map +0 -1
  180. package/dist/preprocessors/mermaid.js.map +0 -1
  181. package/dist/preprocessors/registry.d.ts.map +0 -1
  182. package/dist/preprocessors/registry.js.map +0 -1
  183. package/dist/search-standalone.d.ts.map +0 -1
  184. package/dist/search-standalone.js.map +0 -1
  185. package/dist/search.d.ts.map +0 -1
  186. package/dist/search.js.map +0 -1
  187. package/dist/test-utils.d.ts.map +0 -1
  188. package/dist/test-utils.js.map +0 -1
  189. package/dist/text/chunker.d.ts.map +0 -1
  190. package/dist/text/chunker.js.map +0 -1
  191. package/dist/text/embedder.d.ts.map +0 -1
  192. package/dist/text/embedder.js.map +0 -1
  193. package/dist/text/index.d.ts.map +0 -1
  194. package/dist/text/index.js.map +0 -1
  195. package/dist/text/preprocessors/index.d.ts.map +0 -1
  196. package/dist/text/preprocessors/index.js.map +0 -1
  197. package/dist/text/preprocessors/mdx.d.ts.map +0 -1
  198. package/dist/text/preprocessors/mdx.js.map +0 -1
  199. package/dist/text/preprocessors/mermaid.d.ts.map +0 -1
  200. package/dist/text/preprocessors/mermaid.js.map +0 -1
  201. package/dist/text/preprocessors/registry.d.ts.map +0 -1
  202. package/dist/text/preprocessors/registry.js.map +0 -1
  203. package/dist/text/reranker.d.ts.map +0 -1
  204. package/dist/text/reranker.js.map +0 -1
  205. package/dist/text/tokenizer.d.ts.map +0 -1
  206. package/dist/text/tokenizer.js.map +0 -1
  207. package/dist/types.d.ts.map +0 -1
  208. package/dist/types.js.map +0 -1
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Resource Cleanup Manager - Handles cleanup of temporary files and buffers for failed operations
3
+ * Implements task 8.2: Add resource cleanup for failed operations
4
+ * Requirements: 8.2, 8.4, 9.4
5
+ */
6
+ import { DatabaseConnection } from './db.js';
7
+ /**
8
+ * Resource that needs cleanup
9
+ */
10
+ export interface CleanupResource {
11
+ type: 'file' | 'directory' | 'database_entry' | 'buffer';
12
+ path?: string;
13
+ contentId?: string;
14
+ buffer?: Buffer;
15
+ cleanup: () => Promise<void>;
16
+ }
17
+ /**
18
+ * Transaction context for content operations
19
+ */
20
+ export interface ContentTransaction {
21
+ id: string;
22
+ resources: CleanupResource[];
23
+ isCommitted: boolean;
24
+ isRolledBack: boolean;
25
+ startTime: Date;
26
+ timeoutMs?: number;
27
+ }
28
+ /**
29
+ * Resource cleanup manager for content operations
30
+ */
31
+ export declare class ResourceCleanupManager {
32
+ private activeTransactions;
33
+ private cleanupTimeouts;
34
+ /**
35
+ * Start a new transaction for content operations
36
+ * @param timeoutMs - Optional timeout in milliseconds
37
+ * @returns Transaction ID
38
+ */
39
+ startTransaction(timeoutMs?: number): string;
40
+ /**
41
+ * Add a resource to be tracked for cleanup
42
+ * @param transactionId - Transaction ID
43
+ * @param resource - Resource to track
44
+ */
45
+ addResource(transactionId: string, resource: CleanupResource): void;
46
+ /**
47
+ * Add a temporary file to be tracked for cleanup
48
+ * @param transactionId - Transaction ID
49
+ * @param filePath - Path to temporary file
50
+ */
51
+ addTempFile(transactionId: string, filePath: string): void;
52
+ /**
53
+ * Add a database entry to be tracked for cleanup
54
+ * @param transactionId - Transaction ID
55
+ * @param db - Database connection
56
+ * @param contentId - Content ID to delete
57
+ */
58
+ addDatabaseEntry(transactionId: string, db: DatabaseConnection, contentId: string): void;
59
+ /**
60
+ * Add a buffer to be tracked for cleanup (memory management)
61
+ * @param transactionId - Transaction ID
62
+ * @param buffer - Buffer to clear
63
+ */
64
+ addBuffer(transactionId: string, buffer: Buffer): void;
65
+ /**
66
+ * Commit a transaction - resources will not be cleaned up
67
+ * @param transactionId - Transaction ID
68
+ */
69
+ commitTransaction(transactionId: string): Promise<void>;
70
+ /**
71
+ * Rollback a transaction - cleanup all tracked resources
72
+ * @param transactionId - Transaction ID
73
+ * @param reason - Reason for rollback
74
+ */
75
+ rollbackTransaction(transactionId: string, reason?: string): Promise<void>;
76
+ /**
77
+ * Get transaction status
78
+ * @param transactionId - Transaction ID
79
+ * @returns Transaction status or null if not found
80
+ */
81
+ getTransactionStatus(transactionId: string): {
82
+ id: string;
83
+ resourceCount: number;
84
+ isCommitted: boolean;
85
+ isRolledBack: boolean;
86
+ startTime: Date;
87
+ duration: number;
88
+ timeoutMs?: number;
89
+ } | null;
90
+ /**
91
+ * Cleanup all active transactions (emergency cleanup)
92
+ */
93
+ cleanupAllTransactions(): Promise<void>;
94
+ /**
95
+ * Get statistics about active transactions
96
+ */
97
+ getStatistics(): {
98
+ activeTransactions: number;
99
+ totalResources: number;
100
+ oldestTransactionAge: number | null;
101
+ transactionsWithTimeout: number;
102
+ };
103
+ /**
104
+ * Generate a unique transaction ID
105
+ */
106
+ private generateTransactionId;
107
+ }
108
+ /**
109
+ * Global resource cleanup manager instance
110
+ */
111
+ export declare const globalResourceCleanup: ResourceCleanupManager;
112
+ /**
113
+ * Utility function to execute an operation with automatic resource cleanup
114
+ * @param operation - Operation to execute
115
+ * @param timeoutMs - Optional timeout in milliseconds
116
+ * @returns Promise that resolves to operation result
117
+ */
118
+ export declare function withResourceCleanup<T>(operation: (transactionId: string) => Promise<T>, timeoutMs?: number): Promise<T>;
119
+ /**
120
+ * Utility function for atomic file operations with cleanup
121
+ * @param filePath - Target file path
122
+ * @param content - Content to write
123
+ * @param transactionId - Transaction ID for cleanup tracking
124
+ */
125
+ export declare function writeFileAtomic(filePath: string, content: Buffer, transactionId: string): Promise<void>;
126
+ /**
127
+ * Timeout wrapper for operations
128
+ * @param operation - Operation to execute
129
+ * @param timeoutMs - Timeout in milliseconds
130
+ * @param timeoutMessage - Message for timeout error
131
+ * @returns Promise that resolves to operation result or rejects on timeout
132
+ */
133
+ export declare function withTimeout<T>(operation: Promise<T>, timeoutMs: number, timeoutMessage?: string): Promise<T>;
134
+ /**
135
+ * Memory-safe buffer operations
136
+ */
137
+ export declare class SafeBuffer {
138
+ private buffer;
139
+ private originalBuffer;
140
+ private isCleared;
141
+ private clearOriginal;
142
+ constructor(size: number | Buffer, options?: {
143
+ clearOriginal?: boolean;
144
+ });
145
+ /**
146
+ * Get the buffer (throws if cleared)
147
+ */
148
+ get(): Buffer;
149
+ /**
150
+ * Clear the buffer securely
151
+ * This clears the internal copy and optionally the original buffer for security
152
+ */
153
+ clear(): void;
154
+ /**
155
+ * Get buffer size
156
+ */
157
+ size(): number;
158
+ /**
159
+ * Check if buffer is cleared
160
+ */
161
+ isBufferCleared(): boolean;
162
+ }
163
+ //# sourceMappingURL=resource-cleanup.d.ts.map
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Resource Cleanup Manager - Handles cleanup of temporary files and buffers for failed operations
3
+ * Implements task 8.2: Add resource cleanup for failed operations
4
+ * Requirements: 8.2, 8.4, 9.4
5
+ */
6
+ import { promises as fs } from 'fs';
7
+ import { dirname } from 'path';
8
+ import { deleteContentMetadata } from './db.js';
9
+ import { ContentDirectoryError } from './content-errors.js';
10
+ /**
11
+ * Resource cleanup manager for content operations
12
+ */
13
+ export class ResourceCleanupManager {
14
+ activeTransactions = new Map();
15
+ cleanupTimeouts = new Map();
16
+ /**
17
+ * Start a new transaction for content operations
18
+ * @param timeoutMs - Optional timeout in milliseconds
19
+ * @returns Transaction ID
20
+ */
21
+ startTransaction(timeoutMs) {
22
+ const transactionId = this.generateTransactionId();
23
+ const transaction = {
24
+ id: transactionId,
25
+ resources: [],
26
+ isCommitted: false,
27
+ isRolledBack: false,
28
+ startTime: new Date(),
29
+ timeoutMs
30
+ };
31
+ this.activeTransactions.set(transactionId, transaction);
32
+ // Set up timeout if specified
33
+ if (timeoutMs) {
34
+ const timeout = setTimeout(async () => {
35
+ await this.rollbackTransaction(transactionId, 'Transaction timeout');
36
+ }, timeoutMs);
37
+ this.cleanupTimeouts.set(transactionId, timeout);
38
+ }
39
+ return transactionId;
40
+ }
41
+ /**
42
+ * Add a resource to be tracked for cleanup
43
+ * @param transactionId - Transaction ID
44
+ * @param resource - Resource to track
45
+ */
46
+ addResource(transactionId, resource) {
47
+ const transaction = this.activeTransactions.get(transactionId);
48
+ if (!transaction) {
49
+ throw new Error(`Transaction not found: ${transactionId}`);
50
+ }
51
+ if (transaction.isCommitted || transaction.isRolledBack) {
52
+ throw new Error(`Transaction ${transactionId} is already finalized`);
53
+ }
54
+ transaction.resources.push(resource);
55
+ }
56
+ /**
57
+ * Add a temporary file to be tracked for cleanup
58
+ * @param transactionId - Transaction ID
59
+ * @param filePath - Path to temporary file
60
+ */
61
+ addTempFile(transactionId, filePath) {
62
+ this.addResource(transactionId, {
63
+ type: 'file',
64
+ path: filePath,
65
+ cleanup: async () => {
66
+ try {
67
+ await fs.unlink(filePath);
68
+ }
69
+ catch (error) {
70
+ // Ignore file not found errors
71
+ if (error.code !== 'ENOENT') {
72
+ console.warn(`Failed to cleanup temp file ${filePath}:`, error);
73
+ }
74
+ }
75
+ }
76
+ });
77
+ }
78
+ /**
79
+ * Add a database entry to be tracked for cleanup
80
+ * @param transactionId - Transaction ID
81
+ * @param db - Database connection
82
+ * @param contentId - Content ID to delete
83
+ */
84
+ addDatabaseEntry(transactionId, db, contentId) {
85
+ this.addResource(transactionId, {
86
+ type: 'database_entry',
87
+ contentId,
88
+ cleanup: async () => {
89
+ try {
90
+ await deleteContentMetadata(db, contentId);
91
+ }
92
+ catch (error) {
93
+ console.warn(`Failed to cleanup database entry ${contentId}:`, error);
94
+ }
95
+ }
96
+ });
97
+ }
98
+ /**
99
+ * Add a buffer to be tracked for cleanup (memory management)
100
+ * @param transactionId - Transaction ID
101
+ * @param buffer - Buffer to clear
102
+ */
103
+ addBuffer(transactionId, buffer) {
104
+ this.addResource(transactionId, {
105
+ type: 'buffer',
106
+ buffer,
107
+ cleanup: async () => {
108
+ try {
109
+ // Clear buffer contents for security
110
+ buffer.fill(0);
111
+ }
112
+ catch (error) {
113
+ console.warn('Failed to clear buffer:', error);
114
+ }
115
+ }
116
+ });
117
+ }
118
+ /**
119
+ * Commit a transaction - resources will not be cleaned up
120
+ * @param transactionId - Transaction ID
121
+ */
122
+ async commitTransaction(transactionId) {
123
+ const transaction = this.activeTransactions.get(transactionId);
124
+ if (!transaction) {
125
+ throw new Error(`Transaction not found: ${transactionId}`);
126
+ }
127
+ if (transaction.isRolledBack) {
128
+ throw new Error(`Transaction ${transactionId} was already rolled back`);
129
+ }
130
+ transaction.isCommitted = true;
131
+ // Clear timeout
132
+ const timeout = this.cleanupTimeouts.get(transactionId);
133
+ if (timeout) {
134
+ clearTimeout(timeout);
135
+ this.cleanupTimeouts.delete(transactionId);
136
+ }
137
+ // Remove from active transactions
138
+ this.activeTransactions.delete(transactionId);
139
+ }
140
+ /**
141
+ * Rollback a transaction - cleanup all tracked resources
142
+ * @param transactionId - Transaction ID
143
+ * @param reason - Reason for rollback
144
+ */
145
+ async rollbackTransaction(transactionId, reason) {
146
+ const transaction = this.activeTransactions.get(transactionId);
147
+ if (!transaction) {
148
+ // Transaction might have already been cleaned up
149
+ return;
150
+ }
151
+ if (transaction.isCommitted) {
152
+ throw new Error(`Transaction ${transactionId} was already committed`);
153
+ }
154
+ transaction.isRolledBack = true;
155
+ // Clear timeout
156
+ const timeout = this.cleanupTimeouts.get(transactionId);
157
+ if (timeout) {
158
+ clearTimeout(timeout);
159
+ this.cleanupTimeouts.delete(transactionId);
160
+ }
161
+ // Cleanup all resources
162
+ const cleanupPromises = transaction.resources.map(async (resource) => {
163
+ try {
164
+ await resource.cleanup();
165
+ }
166
+ catch (error) {
167
+ console.warn(`Failed to cleanup resource ${resource.type}:`, error);
168
+ }
169
+ });
170
+ await Promise.allSettled(cleanupPromises);
171
+ // Remove from active transactions
172
+ this.activeTransactions.delete(transactionId);
173
+ if (reason) {
174
+ console.warn(`Transaction ${transactionId} rolled back: ${reason}`);
175
+ }
176
+ }
177
+ /**
178
+ * Get transaction status
179
+ * @param transactionId - Transaction ID
180
+ * @returns Transaction status or null if not found
181
+ */
182
+ getTransactionStatus(transactionId) {
183
+ const transaction = this.activeTransactions.get(transactionId);
184
+ if (!transaction) {
185
+ return null;
186
+ }
187
+ return {
188
+ id: transaction.id,
189
+ resourceCount: transaction.resources.length,
190
+ isCommitted: transaction.isCommitted,
191
+ isRolledBack: transaction.isRolledBack,
192
+ startTime: transaction.startTime,
193
+ duration: Date.now() - transaction.startTime.getTime(),
194
+ timeoutMs: transaction.timeoutMs
195
+ };
196
+ }
197
+ /**
198
+ * Cleanup all active transactions (emergency cleanup)
199
+ */
200
+ async cleanupAllTransactions() {
201
+ const transactionIds = Array.from(this.activeTransactions.keys());
202
+ const cleanupPromises = transactionIds.map(async (transactionId) => {
203
+ try {
204
+ await this.rollbackTransaction(transactionId, 'Emergency cleanup');
205
+ }
206
+ catch (error) {
207
+ console.warn(`Failed to cleanup transaction ${transactionId}:`, error);
208
+ }
209
+ });
210
+ await Promise.allSettled(cleanupPromises);
211
+ }
212
+ /**
213
+ * Get statistics about active transactions
214
+ */
215
+ getStatistics() {
216
+ const transactions = Array.from(this.activeTransactions.values());
217
+ const now = Date.now();
218
+ return {
219
+ activeTransactions: transactions.length,
220
+ totalResources: transactions.reduce((sum, t) => sum + t.resources.length, 0),
221
+ oldestTransactionAge: transactions.length > 0
222
+ ? Math.max(...transactions.map(t => now - t.startTime.getTime()))
223
+ : null,
224
+ transactionsWithTimeout: transactions.filter(t => t.timeoutMs).length
225
+ };
226
+ }
227
+ /**
228
+ * Generate a unique transaction ID
229
+ */
230
+ generateTransactionId() {
231
+ return `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
232
+ }
233
+ }
234
+ /**
235
+ * Global resource cleanup manager instance
236
+ */
237
+ export const globalResourceCleanup = new ResourceCleanupManager();
238
+ /**
239
+ * Utility function to execute an operation with automatic resource cleanup
240
+ * @param operation - Operation to execute
241
+ * @param timeoutMs - Optional timeout in milliseconds
242
+ * @returns Promise that resolves to operation result
243
+ */
244
+ export async function withResourceCleanup(operation, timeoutMs) {
245
+ const transactionId = globalResourceCleanup.startTransaction(timeoutMs);
246
+ try {
247
+ const result = await operation(transactionId);
248
+ await globalResourceCleanup.commitTransaction(transactionId);
249
+ return result;
250
+ }
251
+ catch (error) {
252
+ await globalResourceCleanup.rollbackTransaction(transactionId, `Operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
253
+ throw error;
254
+ }
255
+ }
256
+ /**
257
+ * Utility function for atomic file operations with cleanup
258
+ * @param filePath - Target file path
259
+ * @param content - Content to write
260
+ * @param transactionId - Transaction ID for cleanup tracking
261
+ */
262
+ export async function writeFileAtomic(filePath, content, transactionId) {
263
+ const tempPath = `${filePath}.tmp.${Date.now()}`;
264
+ // Track temp file for cleanup
265
+ globalResourceCleanup.addTempFile(transactionId, tempPath);
266
+ try {
267
+ // Ensure directory exists
268
+ await fs.mkdir(dirname(filePath), { recursive: true });
269
+ // Write to temporary file
270
+ await fs.writeFile(tempPath, content);
271
+ // Atomically move to final location
272
+ await fs.rename(tempPath, filePath);
273
+ // Remove temp file from cleanup list since it was successfully moved
274
+ const transaction = globalResourceCleanup.getTransactionStatus(transactionId);
275
+ if (transaction) {
276
+ // Remove the temp file resource since it's now the final file
277
+ const activeTransaction = globalResourceCleanup.activeTransactions.get(transactionId);
278
+ if (activeTransaction) {
279
+ activeTransaction.resources = activeTransaction.resources.filter((r) => r.path !== tempPath);
280
+ }
281
+ }
282
+ }
283
+ catch (error) {
284
+ // Temp file will be cleaned up automatically by transaction rollback
285
+ throw new ContentDirectoryError('atomic write', `Failed to write file atomically: ${error instanceof Error ? error.message : 'Unknown error'}`, 'file_write');
286
+ }
287
+ }
288
+ /**
289
+ * Timeout wrapper for operations
290
+ * @param operation - Operation to execute
291
+ * @param timeoutMs - Timeout in milliseconds
292
+ * @param timeoutMessage - Message for timeout error
293
+ * @returns Promise that resolves to operation result or rejects on timeout
294
+ */
295
+ export function withTimeout(operation, timeoutMs, timeoutMessage = 'Operation timed out') {
296
+ let timeoutHandle;
297
+ const timeoutPromise = new Promise((_, reject) => {
298
+ timeoutHandle = setTimeout(() => {
299
+ reject(new Error(`${timeoutMessage} (${timeoutMs}ms)`));
300
+ }, timeoutMs);
301
+ });
302
+ return Promise.race([
303
+ operation.finally(() => {
304
+ // Clear timeout when operation completes (success or failure)
305
+ if (timeoutHandle) {
306
+ clearTimeout(timeoutHandle);
307
+ }
308
+ }),
309
+ timeoutPromise
310
+ ]);
311
+ }
312
+ /**
313
+ * Memory-safe buffer operations
314
+ */
315
+ export class SafeBuffer {
316
+ buffer;
317
+ originalBuffer = null;
318
+ isCleared = false;
319
+ clearOriginal;
320
+ constructor(size, options = {}) {
321
+ this.clearOriginal = options.clearOriginal ?? true; // Default to true for security
322
+ if (typeof size === 'number') {
323
+ this.buffer = Buffer.allocUnsafe(size);
324
+ }
325
+ else {
326
+ // Store reference to original buffer for secure clearing (if requested)
327
+ if (this.clearOriginal) {
328
+ this.originalBuffer = size;
329
+ }
330
+ // Create a copy of the buffer to avoid modifying the original during normal operations
331
+ this.buffer = Buffer.from(size);
332
+ }
333
+ }
334
+ /**
335
+ * Get the buffer (throws if cleared)
336
+ */
337
+ get() {
338
+ if (this.isCleared) {
339
+ throw new Error('Buffer has been cleared');
340
+ }
341
+ return this.buffer;
342
+ }
343
+ /**
344
+ * Clear the buffer securely
345
+ * This clears the internal copy and optionally the original buffer for security
346
+ */
347
+ clear() {
348
+ if (!this.isCleared) {
349
+ // Clear the internal buffer
350
+ this.buffer.fill(0);
351
+ // Also clear the original buffer for security (if requested and it exists)
352
+ if (this.clearOriginal && this.originalBuffer) {
353
+ this.originalBuffer.fill(0);
354
+ }
355
+ this.isCleared = true;
356
+ }
357
+ }
358
+ /**
359
+ * Get buffer size
360
+ */
361
+ size() {
362
+ return this.buffer.length;
363
+ }
364
+ /**
365
+ * Check if buffer is cleared
366
+ */
367
+ isBufferCleared() {
368
+ return this.isCleared;
369
+ }
370
+ }
371
+ //# sourceMappingURL=resource-cleanup.js.map