documentation-hub 5.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/.eslintrc.json +43 -0
  2. package/.github/workflows/build.yml +64 -0
  3. package/.github/workflows/ci.yml +39 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/Current.md +97 -0
  6. package/DocHub_Image.png +0 -0
  7. package/README.md +666 -0
  8. package/USER_GUIDE.md +1173 -0
  9. package/Updater.md +311 -0
  10. package/build/256x256.png +0 -0
  11. package/build/512x512.png +0 -0
  12. package/build/app-update.yml +4 -0
  13. package/build/create-icon.js +208 -0
  14. package/build/icon.ico +0 -0
  15. package/build/icon.png +0 -0
  16. package/build/icon_1024x1024.png +0 -0
  17. package/dist/assets/Analytics-BpsG9895.js +1 -0
  18. package/dist/assets/Card-IAZin8kp.js +1 -0
  19. package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
  20. package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
  21. package/dist/assets/Documents-CqZ25axS.js +1 -0
  22. package/dist/assets/Input-l89xwXBi.js +1 -0
  23. package/dist/assets/Reporting-DqdHJY_a.js +1 -0
  24. package/dist/assets/Search-XNbu5z_3.js +1 -0
  25. package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
  26. package/dist/assets/Sessions-ClZOPYNc.js +1 -0
  27. package/dist/assets/Settings-DUEHGURa.js +11 -0
  28. package/dist/assets/index-8xUe8ptc.js +24 -0
  29. package/dist/assets/index-RYyJqF7O.css +1 -0
  30. package/dist/assets/path-BkOl0AGO.js +1 -0
  31. package/dist/assets/promises-ID_B9S-h.js +1 -0
  32. package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
  33. package/dist/assets/useToast-yRSO1dkm.js +1 -0
  34. package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
  35. package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
  36. package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
  37. package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
  38. package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
  39. package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
  40. package/dist/electron/main-CXkNtyv-.js +19789 -0
  41. package/dist/electron/main.js +5 -0
  42. package/dist/electron/preload.js +1 -0
  43. package/dist/icon.png +0 -0
  44. package/dist/index.html +27 -0
  45. package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
  46. package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
  47. package/docs/README.md +115 -0
  48. package/docs/TOC_WIRING_GUIDE.md +344 -0
  49. package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
  50. package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
  51. package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
  52. package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
  53. package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
  54. package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
  55. package/docs/analysis/List_Implementation.md +206 -0
  56. package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
  57. package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
  58. package/docs/analysis/RefactorStyles.md +852 -0
  59. package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
  60. package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
  61. package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
  62. package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
  63. package/docs/analysis/github-issues-to-create.md +237 -0
  64. package/docs/api/API_README.md +538 -0
  65. package/docs/api/API_REFERENCE.md +751 -0
  66. package/docs/api/TYPE_DEFINITIONS.md +869 -0
  67. package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
  68. package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
  69. package/docs/docxmlater-readme.md +1341 -0
  70. package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
  71. package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
  72. package/docs/fixes/README.md +37 -0
  73. package/docs/github-issues/issue-1-body.md +125 -0
  74. package/docs/github-issues/issue-10-body.md +850 -0
  75. package/docs/github-issues/issue-2-body.md +200 -0
  76. package/docs/github-issues/issue-3-body.md +270 -0
  77. package/docs/github-issues/issue-4-body.md +169 -0
  78. package/docs/github-issues/issue-5-body.md +173 -0
  79. package/docs/github-issues/issue-6-body.md +158 -0
  80. package/docs/github-issues/issue-7-body.md +171 -0
  81. package/docs/github-issues/issue-8-body.md +407 -0
  82. package/docs/github-issues/issue-9-body.md +515 -0
  83. package/docs/github-issues/issue-tracker.md +274 -0
  84. package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
  85. package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
  86. package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
  87. package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
  88. package/docs/implementation/RefactorStyles.md +588 -0
  89. package/docs/implementation/implement-plan.md +489 -0
  90. package/docs/implementation/missing-helpers-implementation.md +391 -0
  91. package/docs/implementation/refactor-plan.md +520 -0
  92. package/docs/implementation/session-implementation-complete.md +233 -0
  93. package/docs/implementation/session-management-plan.md +250 -0
  94. package/docs/setup-checklist.md +77 -0
  95. package/docs/versions/changelog.md +345 -0
  96. package/electron/customUpdater.ts +656 -0
  97. package/electron/main.ts +2441 -0
  98. package/electron/memoryConfig.ts +187 -0
  99. package/electron/preload.ts +394 -0
  100. package/electron/proxyConfig.ts +340 -0
  101. package/electron/services/BackupService.ts +452 -0
  102. package/electron/services/DictionaryService.ts +402 -0
  103. package/electron/services/LocalDictionaryLookupService.ts +147 -0
  104. package/electron/services/PowerAutomateApiService.ts +231 -0
  105. package/electron/services/SharePointSyncService.ts +474 -0
  106. package/electron/windowsCertStore.ts +427 -0
  107. package/electron/zscalerConfig.ts +381 -0
  108. package/eslint.config.js +92 -0
  109. package/jest.config.js +52 -0
  110. package/package.json +214 -0
  111. package/postcss.config.mjs +6 -0
  112. package/public/icon.png +0 -0
  113. package/publish-release.ps1 +5 -0
  114. package/renovate.json +30 -0
  115. package/src/App.tsx +216 -0
  116. package/src/__mocks__/p-limit.js +12 -0
  117. package/src/__mocks__/styleMock.js +1 -0
  118. package/src/components/common/BugReportButton.tsx +44 -0
  119. package/src/components/common/BugReportDialog.tsx +193 -0
  120. package/src/components/common/Button.tsx +153 -0
  121. package/src/components/common/Card.tsx +86 -0
  122. package/src/components/common/ColorPickerDialog.tsx +177 -0
  123. package/src/components/common/ConfirmDialog.tsx +96 -0
  124. package/src/components/common/DebugConsole.tsx +275 -0
  125. package/src/components/common/EmptyState.tsx +183 -0
  126. package/src/components/common/ErrorBoundary.tsx +98 -0
  127. package/src/components/common/ErrorDetailsDialog.tsx +153 -0
  128. package/src/components/common/ErrorFallback.tsx +218 -0
  129. package/src/components/common/Input.tsx +109 -0
  130. package/src/components/common/Skeleton.tsx +184 -0
  131. package/src/components/common/SplashScreen.tsx +81 -0
  132. package/src/components/common/Toast.tsx +155 -0
  133. package/src/components/common/Tooltip.tsx +79 -0
  134. package/src/components/common/UpdateNotification.tsx +320 -0
  135. package/src/components/comparison/ComparisonWindow.tsx +374 -0
  136. package/src/components/comparison/SideBySideDiff.tsx +486 -0
  137. package/src/components/comparison/index.ts +8 -0
  138. package/src/components/document/DocumentUploader.tsx +288 -0
  139. package/src/components/document/HyperlinkPreview.tsx +430 -0
  140. package/src/components/document/HyperlinkService.md +1484 -0
  141. package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
  142. package/src/components/document/InlineChangesView.tsx +707 -0
  143. package/src/components/document/ProcessingProgress.tsx +303 -0
  144. package/src/components/document/ProcessingResults.tsx +256 -0
  145. package/src/components/document/TrackedChangesDetail.tsx +530 -0
  146. package/src/components/document/TrackedChangesPanel.tsx +546 -0
  147. package/src/components/document/VirtualDocumentList.tsx +240 -0
  148. package/src/components/editor/DocumentEditor.tsx +723 -0
  149. package/src/components/editor/DocumentEditorModal.tsx +640 -0
  150. package/src/components/editor/EditorQuickActions.tsx +502 -0
  151. package/src/components/editor/EditorToolbar.tsx +312 -0
  152. package/src/components/editor/TableEditor.tsx +926 -0
  153. package/src/components/editor/index.ts +18 -0
  154. package/src/components/layout/Header.tsx +190 -0
  155. package/src/components/layout/Sidebar.tsx +313 -0
  156. package/src/components/layout/TitleBar.tsx +190 -0
  157. package/src/components/navigation/CommandPalette.tsx +233 -0
  158. package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
  159. package/src/components/sessions/ChangeItem.tsx +408 -0
  160. package/src/components/sessions/ChangeViewer.tsx +1155 -0
  161. package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
  162. package/src/components/sessions/ProcessingOptions.tsx +297 -0
  163. package/src/components/sessions/ReplacementsTab.tsx +438 -0
  164. package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
  165. package/src/components/sessions/SessionManager.tsx +188 -0
  166. package/src/components/sessions/StylesEditor.tsx +1335 -0
  167. package/src/components/sessions/TabContainer.tsx +151 -0
  168. package/src/components/sessions/VirtualSessionList.tsx +157 -0
  169. package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
  170. package/src/components/settings/CertificateManager.tsx +410 -0
  171. package/src/components/settings/SegmentedControl.tsx +88 -0
  172. package/src/components/settings/SettingRow.tsx +52 -0
  173. package/src/contexts/GlobalStatsContext.tsx +396 -0
  174. package/src/contexts/SessionContext.tsx +2129 -0
  175. package/src/contexts/ThemeContext.tsx +428 -0
  176. package/src/contexts/UserSettingsContext.tsx +290 -0
  177. package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
  178. package/src/global.d.ts +273 -0
  179. package/src/hooks/useDocumentQueue.tsx +210 -0
  180. package/src/hooks/useToast.tsx +55 -0
  181. package/src/main.tsx +10 -0
  182. package/src/pages/Analytics.tsx +386 -0
  183. package/src/pages/CurrentSession.tsx +1174 -0
  184. package/src/pages/Dashboard.tsx +319 -0
  185. package/src/pages/Documents.tsx +317 -0
  186. package/src/pages/Projects.tsx +250 -0
  187. package/src/pages/Reporting.tsx +386 -0
  188. package/src/pages/Search.tsx +349 -0
  189. package/src/pages/Sessions.tsx +285 -0
  190. package/src/pages/Settings.tsx +2662 -0
  191. package/src/services/HyperlinkService.ts +1085 -0
  192. package/src/services/document/DocXMLaterProcessor.ts +617 -0
  193. package/src/services/document/DocumentProcessingComparison.ts +856 -0
  194. package/src/services/document/DocumentSnapshotService.ts +575 -0
  195. package/src/services/document/WordDocumentProcessor.ts +10509 -0
  196. package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
  197. package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
  198. package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
  199. package/src/services/document/blanklines/BlankLineManager.ts +658 -0
  200. package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
  201. package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
  202. package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
  203. package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
  204. package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
  205. package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
  206. package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
  207. package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
  208. package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
  209. package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
  210. package/src/services/document/blanklines/index.ts +67 -0
  211. package/src/services/document/blanklines/rules/additionRules.ts +337 -0
  212. package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
  213. package/src/services/document/blanklines/rules/removalRules.ts +362 -0
  214. package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
  215. package/src/services/document/blanklines/types.ts +29 -0
  216. package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
  217. package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
  218. package/src/services/document/helpers/whitespace.ts +117 -0
  219. package/src/services/document/list/ListNormalizer.ts +947 -0
  220. package/src/services/document/list/index.ts +45 -0
  221. package/src/services/document/list/list-detection.ts +275 -0
  222. package/src/services/document/list/list-types.ts +162 -0
  223. package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
  224. package/src/services/document/processors/ListProcessor.ts +257 -0
  225. package/src/services/document/processors/StructureProcessor.ts +176 -0
  226. package/src/services/document/processors/StyleProcessor.ts +389 -0
  227. package/src/services/document/processors/TableProcessor.ts +2238 -0
  228. package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
  229. package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
  230. package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
  231. package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
  232. package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
  233. package/src/services/document/processors/index.ts +28 -0
  234. package/src/services/document/types/docx-processing.ts +310 -0
  235. package/src/services/editor/EditorActionHandlers.ts +901 -0
  236. package/src/services/editor/index.ts +13 -0
  237. package/src/setupTests.ts +47 -0
  238. package/src/styles/global.css +782 -0
  239. package/src/types/backup.ts +132 -0
  240. package/src/types/dictionary.ts +125 -0
  241. package/src/types/document-processing.ts +331 -0
  242. package/src/types/docxmlater-augments.d.ts +142 -0
  243. package/src/types/editor.ts +280 -0
  244. package/src/types/electron.ts +340 -0
  245. package/src/types/globalStats.ts +155 -0
  246. package/src/types/hyperlink.ts +471 -0
  247. package/src/types/operations.ts +354 -0
  248. package/src/types/session.ts +427 -0
  249. package/src/types/settings.ts +112 -0
  250. package/src/utils/MemoryMonitor.ts +248 -0
  251. package/src/utils/cn.ts +6 -0
  252. package/src/utils/colorConvert.ts +306 -0
  253. package/src/utils/diffUtils.ts +347 -0
  254. package/src/utils/documentUtils.ts +202 -0
  255. package/src/utils/electronGuard.ts +62 -0
  256. package/src/utils/indexedDB.ts +915 -0
  257. package/src/utils/logger.ts +717 -0
  258. package/src/utils/pathSecurity.ts +232 -0
  259. package/src/utils/pathValidator.ts +236 -0
  260. package/src/utils/processingTimeEstimator.ts +153 -0
  261. package/src/utils/safeJsonParse.ts +62 -0
  262. package/src/utils/textSanitizer.ts +162 -0
  263. package/src/utils/urlHelpers.ts +304 -0
  264. package/src/utils/urlPatterns.ts +198 -0
  265. package/src/utils/urlSanitizer.ts +152 -0
  266. package/src/vite-env.d.ts +11 -0
  267. package/tsconfig.electron.json +19 -0
  268. package/tsconfig.json +36 -0
  269. package/tsconfig.node.json +12 -0
  270. package/typedoc.json +45 -0
  271. package/vite.config.ts +152 -0
@@ -0,0 +1,717 @@
1
+ /**
2
+ * Professional Logging Utility powered by electron-log
3
+ *
4
+ * Features:
5
+ * - File logging with automatic rotation (5MB per file, 5 files max = 25MB total)
6
+ * - Separate logs for main and renderer processes
7
+ * - Environment-aware (debug logs disabled in production)
8
+ * - Colored console output in development
9
+ * - Timestamps and namespaces for better debugging
10
+ * - IPC-safe (renderer logs appear in main console)
11
+ * - Structured logging support
12
+ * - Performance timing utilities
13
+ *
14
+ * Log Locations:
15
+ * - Windows: ~/Documents/Documentation Hub/logs/
16
+ * - macOS: ~/Library/Logs/Documentation Hub/
17
+ * - Linux: ~/.config/Documentation Hub/logs/
18
+ *
19
+ * Usage:
20
+ * ```typescript
21
+ * import { logger } from '@/utils/logger';
22
+ *
23
+ * const log = logger.namespace('MyModule');
24
+ * log.debug('Detailed info'); // Only in development
25
+ * log.info('Important event'); // Always shows
26
+ * log.warn('Warning message');
27
+ * log.error('Error occurred', error);
28
+ *
29
+ * // Performance timing
30
+ * const timer = logger.startTimer('Operation');
31
+ * // ... do work ...
32
+ * timer.end(); // Logs duration
33
+ *
34
+ * // Structured logging
35
+ * log.info('Document processed', { docId: '123', duration: 1234 });
36
+ * ```
37
+ */
38
+
39
+ import electronLog from 'electron-log';
40
+
41
+ // Detect environment
42
+ const isDevelopment = process.env.NODE_ENV !== 'production';
43
+ const isTest = process.env.NODE_ENV === 'test';
44
+
45
+ // Detect if we're in renderer process
46
+ // NOTE: With contextIsolation: true, window.process is not available
47
+ // So we check for window and document (browser-like environment)
48
+ // Main process has 'electron' in process.versions, renderer has window/document
49
+ const isRenderer = typeof window !== 'undefined' && typeof document !== 'undefined';
50
+
51
+ // In renderer process, electron-log only has console transport and uses IPC for file logging
52
+ // In main process, it has both file and console transports
53
+ // We should only configure transports in the main process
54
+ const isMainProcess = !isRenderer;
55
+
56
+ // Only configure electron-log if we're in the main process
57
+ if (isMainProcess) {
58
+ // Prevent EPIPE crashes when stdout/stderr pipes are closed (e.g., during shutdown)
59
+ if (process.stdout && typeof process.stdout.on === 'function') {
60
+ process.stdout.on('error', (err: any) => {
61
+ if (err?.code === 'EPIPE') return;
62
+ });
63
+ }
64
+ if (process.stderr && typeof process.stderr.on === 'function') {
65
+ process.stderr.on('error', (err: any) => {
66
+ if (err?.code === 'EPIPE') return;
67
+ });
68
+ }
69
+
70
+ if (electronLog.transports?.file) {
71
+ electronLog.transports.file.level = 'info';
72
+ electronLog.transports.file.maxSize = 5 * 1024 * 1024; // 5MB per file
73
+ electronLog.transports.file.archiveLogFn = (file: any) => {
74
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
75
+ return file.toString().replace(/\.log$/, `-${timestamp}.log`);
76
+ };
77
+ electronLog.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}] {text}';
78
+ }
79
+
80
+ if (electronLog.transports?.console) {
81
+ electronLog.transports.console.level = isDevelopment ? 'debug' : 'warn';
82
+
83
+ // Wrap console transport writeFn to suppress EPIPE errors
84
+ const originalWriteFn = electronLog.transports.console.writeFn;
85
+ if (typeof originalWriteFn === 'function') {
86
+ electronLog.transports.console.writeFn = function (...args: any[]) {
87
+ try {
88
+ return originalWriteFn.apply(this, args as [any]);
89
+ } catch (err: any) {
90
+ if (err?.code === 'EPIPE') return;
91
+ throw err;
92
+ }
93
+ };
94
+ }
95
+
96
+ // Console configuration (development only)
97
+ if (isDevelopment) {
98
+ electronLog.transports.console.format = '[{h}:{i}:{s}.{ms}] [{level}] {text}';
99
+ electronLog.transports.console.useStyles = true;
100
+ } else {
101
+ // Production: minimal console output
102
+ electronLog.transports.console.format = '[{level}] {text}';
103
+ }
104
+ }
105
+
106
+ // Disable logging in tests
107
+ if (isTest && electronLog.transports?.file && electronLog.transports?.console) {
108
+ electronLog.transports.file.level = false;
109
+ electronLog.transports.console.level = false;
110
+ }
111
+ } else {
112
+ // Renderer process: Use console transport only, electron-log handles IPC automatically
113
+ // This prevents the "logger isn't initialized in main process" error
114
+ if (electronLog.transports?.console) {
115
+ electronLog.transports.console.level = isDevelopment ? 'debug' : 'warn';
116
+ electronLog.transports.console.format = '[{h}:{i}:{s}.{ms}] [{level}] {text}';
117
+ }
118
+
119
+ // Disable file transport attempts in renderer (it uses IPC automatically when available)
120
+ if (electronLog.transports?.file) {
121
+ electronLog.transports.file.level = false;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * SECURITY: Sanitize log data to prevent sensitive information exposure
127
+ *
128
+ * Redacts:
129
+ * - File paths (Windows: C:\..., Unix: /home/...)
130
+ * - API endpoints and URLs
131
+ * - Document content (truncates long strings)
132
+ * - Sensitive field names (apiEndpoint, filePath, documentPath, token, password, etc.)
133
+ *
134
+ * @param data - Any data to be logged
135
+ * @returns Sanitized version safe for logging
136
+ */
137
+ function sanitizeLogData(data: any): any {
138
+ // Handle null/undefined
139
+ if (data == null) {
140
+ return data;
141
+ }
142
+
143
+ // Handle primitive types
144
+ if (typeof data === 'string') {
145
+ let sanitized = data;
146
+
147
+ // Redact Windows file paths (C:\Users\..., D:\Documents\..., etc.)
148
+ sanitized = sanitized.replace(/[A-Z]:\\[^\s"'<>|*?]+/gi, '[REDACTED_PATH]');
149
+
150
+ // Redact UNC paths (\\server\share\...)
151
+ sanitized = sanitized.replace(/\\\\[^\s"'<>|*?]+/g, '[REDACTED_PATH]');
152
+
153
+ // Redact Unix file paths (/home/..., /Users/..., /var/..., etc.)
154
+ sanitized = sanitized.replace(/\/(home|Users|var|tmp|opt)\/[\w\s\-./]+/gi, '[REDACTED_PATH]');
155
+
156
+ // Redact full URLs (but keep domain for debugging)
157
+ sanitized = sanitized.replace(/(https?:\/\/[^/\s]+)(\/[^\s]*)/gi, '$1/[REDACTED_URL]');
158
+
159
+ // Truncate very long strings (likely document content)
160
+ if (sanitized.length > 500) {
161
+ sanitized = sanitized.substring(0, 500) + '... [TRUNCATED]';
162
+ }
163
+
164
+ return sanitized;
165
+ }
166
+
167
+ // Handle arrays
168
+ if (Array.isArray(data)) {
169
+ return data.map((item) => sanitizeLogData(item));
170
+ }
171
+
172
+ // Handle objects
173
+ if (typeof data === 'object') {
174
+ const sanitized: any = {};
175
+ const sensitiveKeys = [
176
+ 'apiEndpoint',
177
+ 'apiUrl',
178
+ 'filePath',
179
+ 'documentPath',
180
+ 'path',
181
+ 'fullPath',
182
+ 'token',
183
+ 'accessToken',
184
+ 'refreshToken',
185
+ 'apiKey',
186
+ 'password',
187
+ 'secret',
188
+ 'clientSecret',
189
+ 'authorization',
190
+ 'bearer',
191
+ 'cookie',
192
+ 'sessionId',
193
+ 'userId',
194
+ 'email',
195
+ 'username',
196
+ 'connectionString',
197
+ 'privateKey',
198
+ 'credential',
199
+ ];
200
+
201
+ for (const [key, value] of Object.entries(data)) {
202
+ // Redact sensitive fields entirely
203
+ if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk.toLowerCase()))) {
204
+ sanitized[key] = '[REDACTED]';
205
+ } else {
206
+ // Recursively sanitize nested objects
207
+ sanitized[key] = sanitizeLogData(value);
208
+ }
209
+ }
210
+
211
+ return sanitized;
212
+ }
213
+
214
+ // Return other types (numbers, booleans) as-is
215
+ return data;
216
+ }
217
+
218
+ /**
219
+ * Get formatted timestamp for manual logging
220
+ */
221
+ function getTimestamp(): string {
222
+ const now = new Date();
223
+ const hours = String(now.getHours()).padStart(2, '0');
224
+ const minutes = String(now.getMinutes()).padStart(2, '0');
225
+ const seconds = String(now.getSeconds()).padStart(2, '0');
226
+ const ms = String(now.getMilliseconds()).padStart(3, '0');
227
+ return `${hours}:${minutes}:${seconds}.${ms}`;
228
+ }
229
+
230
+ /**
231
+ * Create a scoped logger for a specific module
232
+ */
233
+ function createScopedLogger(scope: string) {
234
+ // In renderer, only use console logging to avoid "not initialized" errors
235
+ // electron-log will automatically send logs to main process via IPC when properly set up
236
+ const useElectronLog = isMainProcess;
237
+ const scopedLog = useElectronLog ? electronLog.scope(scope) : null;
238
+
239
+ return {
240
+ /**
241
+ * Debug level - only enabled in development
242
+ * Use for detailed diagnostic information
243
+ */
244
+ debug(message: string, ...args: any[]): void {
245
+ if (isDevelopment && !isTest) {
246
+ // SECURITY: Sanitize all arguments before logging
247
+ const sanitizedArgs = args.map(sanitizeLogData);
248
+ const sanitizedMessage = sanitizeLogData(message);
249
+
250
+ if (scopedLog) {
251
+ scopedLog.debug(sanitizedMessage, ...sanitizedArgs);
252
+ } else {
253
+ // Renderer fallback: use console directly
254
+ console.debug(`[${scope}] [DEBUG] ${sanitizedMessage}`, ...sanitizedArgs);
255
+ }
256
+ }
257
+ },
258
+
259
+ /**
260
+ * Info level - general informational messages
261
+ * Enabled in all environments
262
+ */
263
+ info(message: string, ...args: any[]): void {
264
+ if (!isTest) {
265
+ // SECURITY: Sanitize all arguments before logging
266
+ const sanitizedArgs = args.map(sanitizeLogData);
267
+ const sanitizedMessage = sanitizeLogData(message);
268
+
269
+ if (scopedLog) {
270
+ scopedLog.info(sanitizedMessage, ...sanitizedArgs);
271
+ } else {
272
+ console.info(`[${scope}] [INFO] ${sanitizedMessage}`, ...sanitizedArgs);
273
+ }
274
+ }
275
+ },
276
+
277
+ /**
278
+ * Warning level - potentially harmful situations
279
+ * Enabled in all environments
280
+ */
281
+ warn(message: string, ...args: any[]): void {
282
+ if (!isTest) {
283
+ // SECURITY: Sanitize all arguments before logging
284
+ const sanitizedArgs = args.map(sanitizeLogData);
285
+ const sanitizedMessage = sanitizeLogData(message);
286
+
287
+ if (scopedLog) {
288
+ scopedLog.warn(sanitizedMessage, ...sanitizedArgs);
289
+ } else {
290
+ console.warn(`[${scope}] [WARN] ${sanitizedMessage}`, ...sanitizedArgs);
291
+ }
292
+ }
293
+ },
294
+
295
+ /**
296
+ * Error level - error events
297
+ * Always enabled
298
+ */
299
+ error(message: string, ...args: any[]): void {
300
+ // SECURITY: Sanitize all arguments before logging
301
+ const sanitizedArgs = args.map(sanitizeLogData);
302
+ const sanitizedMessage = sanitizeLogData(message);
303
+
304
+ if (scopedLog) {
305
+ scopedLog.error(sanitizedMessage, ...sanitizedArgs);
306
+ } else {
307
+ console.error(`[${scope}] [ERROR] ${sanitizedMessage}`, ...sanitizedArgs);
308
+ }
309
+ },
310
+
311
+ /**
312
+ * Verbose level - very detailed logs
313
+ * Only in development with explicit enable
314
+ */
315
+ verbose(message: string, ...args: any[]): void {
316
+ if (isDevelopment && !isTest) {
317
+ const sanitizedArgs = args.map(sanitizeLogData);
318
+ const sanitizedMessage = sanitizeLogData(message);
319
+ if (scopedLog) {
320
+ scopedLog.verbose(sanitizedMessage, ...sanitizedArgs);
321
+ } else {
322
+ console.log(`[${scope}] [VERBOSE] ${sanitizedMessage}`, ...sanitizedArgs);
323
+ }
324
+ }
325
+ },
326
+
327
+ /**
328
+ * Silly level - extremely detailed logs
329
+ * Only in development with explicit enable
330
+ */
331
+ silly(message: string, ...args: any[]): void {
332
+ if (isDevelopment && !isTest) {
333
+ const sanitizedArgs = args.map(sanitizeLogData);
334
+ const sanitizedMessage = sanitizeLogData(message);
335
+ if (scopedLog) {
336
+ scopedLog.silly(sanitizedMessage, ...sanitizedArgs);
337
+ } else {
338
+ console.log(`[${scope}] [SILLY] ${sanitizedMessage}`, ...sanitizedArgs);
339
+ }
340
+ }
341
+ },
342
+ };
343
+ }
344
+
345
+ /**
346
+ * Main logger export with utility methods
347
+ */
348
+ export const logger = {
349
+ /**
350
+ * Debug level logging - only enabled in development
351
+ */
352
+ debug(message: string, ...args: any[]): void {
353
+ if (isDevelopment && !isTest) {
354
+ if (isMainProcess) {
355
+ electronLog.debug(message, ...args);
356
+ } else {
357
+ console.debug(`[DEBUG] ${message}`, ...args);
358
+ }
359
+ }
360
+ },
361
+
362
+ /**
363
+ * Info level logging - enabled in all environments
364
+ */
365
+ info(message: string, ...args: any[]): void {
366
+ if (!isTest) {
367
+ if (isMainProcess) {
368
+ electronLog.info(message, ...args);
369
+ } else {
370
+ console.info(`[INFO] ${message}`, ...args);
371
+ }
372
+ }
373
+ },
374
+
375
+ /**
376
+ * Warning level logging - enabled in all environments
377
+ */
378
+ warn(message: string, ...args: any[]): void {
379
+ if (!isTest) {
380
+ if (isMainProcess) {
381
+ electronLog.warn(message, ...args);
382
+ } else {
383
+ console.warn(`[WARN] ${message}`, ...args);
384
+ }
385
+ }
386
+ },
387
+
388
+ /**
389
+ * Error level logging - always enabled
390
+ */
391
+ error(message: string, ...args: any[]): void {
392
+ if (isMainProcess) {
393
+ electronLog.error(message, ...args);
394
+ } else {
395
+ console.error(`[ERROR] ${message}`, ...args);
396
+ }
397
+ },
398
+
399
+ /**
400
+ * Verbose level logging
401
+ */
402
+ verbose(message: string, ...args: any[]): void {
403
+ if (isDevelopment && !isTest) {
404
+ if (isMainProcess) {
405
+ electronLog.verbose(message, ...args);
406
+ } else {
407
+ console.log(`[VERBOSE] ${message}`, ...args);
408
+ }
409
+ }
410
+ },
411
+
412
+ /**
413
+ * Create a namespaced logger for specific modules
414
+ *
415
+ * @example
416
+ * const log = logger.namespace('DocumentProcessor');
417
+ * log.info('Processing started');
418
+ */
419
+ namespace(name: string) {
420
+ return createScopedLogger(name);
421
+ },
422
+
423
+ /**
424
+ * Create a scoped logger (alias for namespace)
425
+ */
426
+ scope(name: string) {
427
+ return createScopedLogger(name);
428
+ },
429
+
430
+ /**
431
+ * Get the path to the log file
432
+ */
433
+ getLogPath(): string {
434
+ if (electronLog.transports?.file) {
435
+ return electronLog.transports.file.getFile().path;
436
+ }
437
+ return 'Logs not available in renderer';
438
+ },
439
+
440
+ /**
441
+ * Set log level dynamically at runtime
442
+ *
443
+ * @param level - Log level (error, warn, info, debug, verbose, silly, false)
444
+ */
445
+ setLevel(level: 'error' | 'warn' | 'info' | 'debug' | 'verbose' | 'silly' | false): void {
446
+ if (electronLog.transports?.file) {
447
+ electronLog.transports.file.level = level;
448
+ }
449
+ if (electronLog.transports?.console) {
450
+ electronLog.transports.console.level = level;
451
+ }
452
+ },
453
+
454
+ /**
455
+ * Enable or disable file logging
456
+ */
457
+ setFileLogging(enabled: boolean): void {
458
+ if (electronLog.transports?.file) {
459
+ electronLog.transports.file.level = enabled ? 'info' : false;
460
+ }
461
+ },
462
+
463
+ /**
464
+ * Clear all log files
465
+ * Note: This function uses dynamic imports to avoid bundling Node.js modules in renderer
466
+ */
467
+ async clearLogs(): Promise<void> {
468
+ try {
469
+ if (!electronLog.transports?.file?.getFile) {
470
+ throw new Error('File logging not available');
471
+ }
472
+
473
+ // Dynamic imports to avoid Vite bundling Node.js built-ins
474
+ const fs = await import('fs/promises');
475
+ const path = await import('path');
476
+
477
+ const logPath = electronLog.transports.file.getFile().path;
478
+ const logDir = path.dirname(logPath);
479
+
480
+ const files = await fs.readdir(logDir);
481
+ for (const file of files) {
482
+ if (file.endsWith('.log')) {
483
+ await fs.unlink(path.join(logDir, file));
484
+ }
485
+ }
486
+
487
+ electronLog.info('Log files cleared');
488
+ } catch (error) {
489
+ electronLog.error('Failed to clear logs:', error);
490
+ }
491
+ },
492
+ };
493
+
494
+ /**
495
+ * Performance measurement utility
496
+ * Use to measure execution time of operations
497
+ *
498
+ * @example
499
+ * const timer = startTimer('Document Processing');
500
+ * await processDocument();
501
+ * timer.end(); // Logs: "[DocumentProcessing] took 1234ms"
502
+ */
503
+ export function startTimer(operationName: string) {
504
+ const start = performance.now();
505
+ const log = logger.namespace('Timer');
506
+
507
+ return {
508
+ /**
509
+ * End the timer and log the duration
510
+ */
511
+ end(): number {
512
+ const duration = Math.round(performance.now() - start);
513
+ log.debug(`${operationName} took ${duration}ms`);
514
+ return duration;
515
+ },
516
+
517
+ /**
518
+ * Get current elapsed time without logging
519
+ */
520
+ elapsed(): number {
521
+ return Math.round(performance.now() - start);
522
+ },
523
+ };
524
+ }
525
+
526
+ /**
527
+ * Direct access to electron-log for advanced usage
528
+ * Only use if you need features not exposed by the wrapper
529
+ */
530
+ export const electronLogger = electronLog;
531
+
532
+ // Export for backward compatibility
533
+ export default logger;
534
+
535
+ // ============================================================================
536
+ // DEBUG MODE UTILITIES
537
+ // Toggleable verbose logging for specific subsystems
538
+ // ============================================================================
539
+
540
+ /**
541
+ * Debug mode flags for enabling verbose logging in specific areas.
542
+ * These can be toggled at runtime via localStorage for troubleshooting.
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * import { debugModes, setDebugMode, isDebugEnabled } from '@/utils/logger';
547
+ *
548
+ * // Enable document processing debug logs
549
+ * setDebugMode(debugModes.DOCUMENT_PROCESSING, true);
550
+ *
551
+ * // Check if debug is enabled before verbose logging
552
+ * if (isDebugEnabled(debugModes.SESSION_STATE)) {
553
+ * log.debug('Detailed session state:', state);
554
+ * }
555
+ * ```
556
+ */
557
+ export const debugModes = {
558
+ /** Verbose logging for document processing operations */
559
+ DOCUMENT_PROCESSING: 'debug:documentProcessing',
560
+ /** Verbose logging for session state transitions */
561
+ SESSION_STATE: 'debug:sessionState',
562
+ /** Verbose logging for IPC calls between main/renderer */
563
+ IPC_CALLS: 'debug:ipcCalls',
564
+ /** Verbose logging for IndexedDB operations */
565
+ DATABASE: 'debug:database',
566
+ /** Verbose logging for hyperlink operations */
567
+ HYPERLINKS: 'debug:hyperlinks',
568
+ /** Verbose logging for backup operations */
569
+ BACKUPS: 'debug:backups',
570
+ /** Verbose logging for list/bullet processing operations */
571
+ LIST_PROCESSING: 'debug:listProcessing',
572
+ } as const;
573
+
574
+ export type DebugMode = (typeof debugModes)[keyof typeof debugModes];
575
+
576
+ /**
577
+ * Check if a specific debug mode is enabled.
578
+ *
579
+ * @param mode - The debug mode to check (use debugModes constants)
580
+ * @returns true if the debug mode is enabled
581
+ *
582
+ * @example
583
+ * ```typescript
584
+ * if (isDebugEnabled(debugModes.DOCUMENT_PROCESSING)) {
585
+ * log.debug('Processing details:', { step: 1, data: processingData });
586
+ * }
587
+ * ```
588
+ */
589
+ export function isDebugEnabled(mode: DebugMode): boolean {
590
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
591
+ return false;
592
+ }
593
+ return localStorage.getItem(mode) === 'true';
594
+ }
595
+
596
+ /**
597
+ * Enable or disable a specific debug mode.
598
+ *
599
+ * @param mode - The debug mode to set (use debugModes constants)
600
+ * @param enabled - Whether to enable (true) or disable (false) the mode
601
+ *
602
+ * @example
603
+ * ```typescript
604
+ * // Enable debug mode for troubleshooting
605
+ * setDebugMode(debugModes.SESSION_STATE, true);
606
+ *
607
+ * // Disable when done
608
+ * setDebugMode(debugModes.SESSION_STATE, false);
609
+ * ```
610
+ */
611
+ export function setDebugMode(mode: DebugMode, enabled: boolean): void {
612
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
613
+ return;
614
+ }
615
+ if (enabled) {
616
+ localStorage.setItem(mode, 'true');
617
+ } else {
618
+ localStorage.removeItem(mode);
619
+ }
620
+ const log = logger.namespace('Debug');
621
+ log.info(`Debug mode ${mode} ${enabled ? 'enabled' : 'disabled'}`);
622
+ }
623
+
624
+ /**
625
+ * Get all currently enabled debug modes.
626
+ *
627
+ * @returns Array of enabled debug mode keys
628
+ *
629
+ * @example
630
+ * ```typescript
631
+ * const enabled = getEnabledDebugModes();
632
+ * console.log('Active debug modes:', enabled);
633
+ * // Output: ['debug:documentProcessing', 'debug:hyperlinks']
634
+ * ```
635
+ */
636
+ export function getEnabledDebugModes(): DebugMode[] {
637
+ if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
638
+ return [];
639
+ }
640
+ return Object.values(debugModes).filter(
641
+ (mode) => localStorage.getItem(mode) === 'true'
642
+ ) as DebugMode[];
643
+ }
644
+
645
+ /**
646
+ * Disable all debug modes.
647
+ * Useful for resetting debug state after troubleshooting.
648
+ */
649
+ export function disableAllDebugModes(): void {
650
+ const log = logger.namespace('Debug');
651
+ Object.values(debugModes).forEach((mode) => {
652
+ if (typeof localStorage !== 'undefined') {
653
+ localStorage.removeItem(mode);
654
+ }
655
+ });
656
+ log.info('All debug modes disabled');
657
+ }
658
+
659
+ /**
660
+ * Create a conditional logger that only logs when a debug mode is enabled.
661
+ * Useful for adding verbose debug logging without impacting performance.
662
+ *
663
+ * @param mode - The debug mode that controls this logger
664
+ * @param namespace - The namespace for log messages
665
+ * @returns A logger that only logs when the mode is enabled
666
+ *
667
+ * @example
668
+ * ```typescript
669
+ * const debugLog = createDebugLogger(debugModes.DOCUMENT_PROCESSING, 'DocProcessor');
670
+ *
671
+ * // These only log when debug:documentProcessing is enabled
672
+ * debugLog.debug('Step 1: Loading document');
673
+ * debugLog.info('Processing complete', { stats });
674
+ * ```
675
+ */
676
+ export function createDebugLogger(mode: DebugMode, namespace: string) {
677
+ const log = logger.namespace(namespace);
678
+
679
+ return {
680
+ debug: (...args: unknown[]) => {
681
+ if (isDebugEnabled(mode)) (log.debug as (...args: unknown[]) => void)(...args);
682
+ },
683
+ info: (...args: unknown[]) => {
684
+ if (isDebugEnabled(mode)) (log.info as (...args: unknown[]) => void)(...args);
685
+ },
686
+ warn: (...args: unknown[]) => {
687
+ // Warnings always log
688
+ (log.warn as (...args: unknown[]) => void)(...args);
689
+ },
690
+ error: (...args: unknown[]) => {
691
+ // Errors always log
692
+ (log.error as (...args: unknown[]) => void)(...args);
693
+ },
694
+ };
695
+ }
696
+
697
+ /**
698
+ * Initialize logging on startup (call from main process)
699
+ */
700
+ export function initializeLogging(): void {
701
+ const log = logger.namespace('Logger');
702
+
703
+ log.info('═══════════════════════════════════════════════════════════');
704
+ log.info(' Documentation Hub - Logging Initialized');
705
+ log.info('═══════════════════════════════════════════════════════════');
706
+ log.info(`Environment: ${process.env.NODE_ENV || 'development'}`);
707
+ log.info(`Process: ${isRenderer ? 'Renderer' : 'Main'}`);
708
+
709
+ if (electronLog.transports?.file) {
710
+ log.info(`Log file: ${electronLog.transports.file.getFile().path}`);
711
+ log.info(
712
+ `Log level: File=${electronLog.transports.file.level}, Console=${electronLog.transports.console?.level || 'N/A'}`
713
+ );
714
+ }
715
+
716
+ log.info('═══════════════════════════════════════════════════════════');
717
+ }