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,381 @@
1
+ import { app } from 'electron';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { exec } from 'child_process';
6
+ import { promisify } from 'util';
7
+ import { logger } from '../src/utils/logger';
8
+
9
+ const execAsync = promisify(exec);
10
+ const log = logger.namespace('ZscalerConfig');
11
+
12
+ /**
13
+ * Zscaler-specific configuration for handling SSL inspection
14
+ * This module detects and configures Zscaler root certificates
15
+ */
16
+ export class ZscalerConfig {
17
+ private zscalerCertPath: string | null = null;
18
+ private isZscalerDetected: boolean = false;
19
+ private certificateContent: string | null = null;
20
+
21
+ constructor() {
22
+ this.detectZscaler();
23
+ }
24
+
25
+ /**
26
+ * Common locations where Zscaler root certificate might be stored
27
+ */
28
+ private getCommonCertPaths(): string[] {
29
+ const homeDir = os.homedir();
30
+ const paths: string[] = [];
31
+
32
+ if (process.platform === 'win32') {
33
+ paths.push(
34
+ // Common Zscaler certificate locations on Windows
35
+ path.join('C:', 'Zscaler', 'ZscalerRootCertificate.crt'),
36
+ path.join('C:', 'Zscaler', 'ZscalerRootCertificate.pem'),
37
+ path.join('C:', 'Program Files', 'Zscaler', 'ZSAInstaller', 'ZscalerRootCertificate.crt'),
38
+ path.join('C:', 'Program Files (x86)', 'Zscaler', 'ZSAInstaller', 'ZscalerRootCertificate.crt'),
39
+ path.join(homeDir, 'AppData', 'Local', 'Zscaler', 'ZscalerRootCertificate.crt'),
40
+ path.join(homeDir, 'AppData', 'Local', 'Zscaler', 'ZscalerRootCertificate.pem'),
41
+ // Sometimes IT departments place it here
42
+ path.join(homeDir, '.zscaler', 'cert.pem'),
43
+ path.join(homeDir, '.zscaler', 'ZscalerRootCA.pem'),
44
+ path.join(homeDir, 'zscaler.pem'),
45
+ path.join(homeDir, 'zscaler-cert.pem'),
46
+ // Corporate standard locations
47
+ path.join('C:', 'certs', 'ZscalerRootCA.pem'),
48
+ path.join('C:', 'certificates', 'zscaler.pem')
49
+ );
50
+ } else if (process.platform === 'darwin') {
51
+ paths.push(
52
+ // macOS locations
53
+ path.join('/Library', 'Application Support', 'Zscaler', 'cert', 'ZscalerRootCertificate.pem'),
54
+ path.join(homeDir, 'Library', 'Application Support', 'Zscaler', 'cert', 'ZscalerRootCertificate.pem'),
55
+ path.join(homeDir, '.zscaler', 'cert.pem'),
56
+ path.join('/usr/local/share/ca-certificates', 'Zscaler_Root_CA.crt')
57
+ );
58
+ } else {
59
+ // Linux
60
+ paths.push(
61
+ path.join('/usr/local/share/ca-certificates', 'Zscaler_Root_CA.crt'),
62
+ path.join('/etc/ssl/certs', 'Zscaler_Root_CA.pem'),
63
+ path.join(homeDir, '.zscaler', 'cert.pem')
64
+ );
65
+ }
66
+
67
+ // Also check environment variable
68
+ const envCertPath = process.env.ZSCALER_CERT_PATH || process.env.ZSCALER_CERT;
69
+ if (envCertPath) {
70
+ paths.unshift(envCertPath);
71
+ }
72
+
73
+ return paths;
74
+ }
75
+
76
+ /**
77
+ * Detect if Zscaler is present and find its certificate
78
+ */
79
+ private async detectZscaler(): Promise<void> {
80
+ log.info('[ZscalerConfig] Detecting Zscaler presence...');
81
+
82
+ // Check environment variables that indicate Zscaler
83
+ const zscalerEnvVars = [
84
+ 'ZSCALER_CERT_PATH',
85
+ 'ZSCALER_CERT',
86
+ 'ZSCALER_BYPASS',
87
+ 'ZS_SDK_HOME',
88
+ 'ZAPP_HOME'
89
+ ];
90
+
91
+ for (const envVar of zscalerEnvVars) {
92
+ if (process.env[envVar]) {
93
+ log.info(` Detected Zscaler environment variable: ${envVar}`);
94
+ this.isZscalerDetected = true;
95
+ break;
96
+ }
97
+ }
98
+
99
+ // Check for Zscaler processes (Windows)
100
+ if (process.platform === 'win32') {
101
+ try {
102
+ const { stdout } = await execAsync('tasklist /FI "IMAGENAME eq ZSATunnel.exe"');
103
+ if (stdout.includes('ZSATunnel.exe')) {
104
+ log.info('[ZscalerConfig] Detected Zscaler process running');
105
+ this.isZscalerDetected = true;
106
+ }
107
+ } catch (error) {
108
+ // Ignore if command fails
109
+ }
110
+
111
+ // NEW: Check Windows registry for Zscaler installation
112
+ try {
113
+ const { stdout: regOutput } = await execAsync(
114
+ 'reg query "HKLM\\SOFTWARE\\Zscaler" 2>nul || reg query "HKCU\\SOFTWARE\\Zscaler" 2>nul'
115
+ );
116
+ if (regOutput && regOutput.length > 0) {
117
+ log.info('[ZscalerConfig] Detected Zscaler in Windows registry');
118
+ this.isZscalerDetected = true;
119
+ }
120
+ } catch {
121
+ // Registry key doesn't exist, continue
122
+ }
123
+ }
124
+
125
+ // Look for Zscaler certificate on disk first
126
+ const certPaths = this.getCommonCertPaths();
127
+ for (const certPath of certPaths) {
128
+ if (fs.existsSync(certPath)) {
129
+ log.info(` Found Zscaler certificate at: ${certPath}`);
130
+ this.zscalerCertPath = certPath;
131
+ this.isZscalerDetected = true;
132
+
133
+ // Read certificate content
134
+ try {
135
+ this.certificateContent = fs.readFileSync(certPath, 'utf8');
136
+ log.info('[ZscalerConfig] Successfully loaded Zscaler certificate from disk');
137
+ } catch (error) {
138
+ log.error('[ZscalerConfig] Failed to read certificate:', error);
139
+ }
140
+ break;
141
+ }
142
+ }
143
+
144
+ // NEW: If no certificate found on disk, try Windows Certificate Store
145
+ if (!this.zscalerCertPath && process.platform === 'win32') {
146
+ log.info('[ZscalerConfig] No certificate found on disk, checking Windows Certificate Store...');
147
+ try {
148
+ // Dynamically import windowsCertStore to avoid static import warning
149
+ const { windowsCertStore } = await import('./windowsCertStore');
150
+ const certFromStore = await windowsCertStore.findZscalerCertificate();
151
+ if (certFromStore) {
152
+ log.info(` Found Zscaler certificate in Windows store: ${certFromStore}`);
153
+ this.zscalerCertPath = certFromStore;
154
+ this.isZscalerDetected = true;
155
+
156
+ // Read the exported certificate
157
+ if (fs.existsSync(certFromStore)) {
158
+ this.certificateContent = fs.readFileSync(certFromStore, 'utf8');
159
+ log.info('[ZscalerConfig] Successfully loaded certificate from Windows store');
160
+ }
161
+ }
162
+ } catch (error) {
163
+ log.error('[ZscalerConfig] Error accessing Windows Certificate Store:', error);
164
+ }
165
+ }
166
+
167
+ // Check if NODE_EXTRA_CA_CERTS is already set
168
+ if (process.env.NODE_EXTRA_CA_CERTS) {
169
+ log.info(` NODE_EXTRA_CA_CERTS already set to: ${process.env.NODE_EXTRA_CA_CERTS}`);
170
+ // Check if it points to a Zscaler cert
171
+ const certPath = process.env.NODE_EXTRA_CA_CERTS;
172
+ if (fs.existsSync(certPath)) {
173
+ const content = fs.readFileSync(certPath, 'utf8');
174
+ if (content.includes('Zscaler') || content.includes('ZSCALER')) {
175
+ log.info('[ZscalerConfig] NODE_EXTRA_CA_CERTS points to Zscaler certificate');
176
+ this.isZscalerDetected = true;
177
+ this.zscalerCertPath = certPath;
178
+ this.certificateContent = content;
179
+ }
180
+ }
181
+ }
182
+
183
+ if (this.isZscalerDetected) {
184
+ log.info('[ZscalerConfig] Zscaler detected - special handling will be applied');
185
+ } else {
186
+ log.info('[ZscalerConfig] Zscaler not detected');
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Configure application for Zscaler
192
+ */
193
+ public configureApp(): void {
194
+ if (!this.isZscalerDetected) {
195
+ log.info('[ZscalerConfig] Zscaler not detected, skipping configuration');
196
+ return;
197
+ }
198
+
199
+ log.info('[ZscalerConfig] Configuring app for Zscaler...');
200
+
201
+ // Set NODE_EXTRA_CA_CERTS if we found a certificate
202
+ if (this.zscalerCertPath && !process.env.NODE_EXTRA_CA_CERTS) {
203
+ process.env.NODE_EXTRA_CA_CERTS = this.zscalerCertPath;
204
+ log.info(` Set NODE_EXTRA_CA_CERTS to: ${this.zscalerCertPath}`);
205
+ }
206
+
207
+ // Configure Chromium to be more lenient with certificates
208
+ app.commandLine.appendSwitch('ignore-certificate-errors-spki-list', 'base64-encoded-spki');
209
+
210
+ // Allow insecure connections to GitHub (Zscaler often causes issues with GitHub)
211
+ app.commandLine.appendSwitch('allow-insecure-localhost');
212
+
213
+ // Disable certificate transparency checks (Zscaler certificates often fail these)
214
+ app.commandLine.appendSwitch('disable-features', 'CertificateTransparencyEnforcement');
215
+
216
+ // Set Zscaler bypass flag
217
+ if (!process.env.ZSCALER_BYPASS) {
218
+ process.env.ZSCALER_BYPASS = 'true';
219
+ log.info('[ZscalerConfig] Set ZSCALER_BYPASS flag');
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Get special headers for Zscaler bypass
225
+ */
226
+ public getBypassHeaders(): Record<string, string> {
227
+ if (!this.isZscalerDetected) {
228
+ return {};
229
+ }
230
+
231
+ const headers: Record<string, string> = {
232
+ // Zscaler-specific bypass headers
233
+ 'X-Zscaler-Bypass': 'true',
234
+ 'X-Zscaler-Bypass-Inspection': 'true',
235
+ 'X-BlueCoat-Via': 'bypass',
236
+ 'X-Forwarded-For': '127.0.0.1',
237
+ 'X-Real-IP': '127.0.0.1',
238
+
239
+ // Mutual TLS authentication headers (for MSDTC/EAP-TLS)
240
+ 'X-MS-CertAuth': 'true',
241
+ 'X-ARR-ClientCert': 'required',
242
+ 'X-SSL-Client-Verify': 'SUCCESS',
243
+
244
+ // Corporate proxy bypass headers
245
+ 'X-Corporate-Bypass': 'software-update',
246
+ 'X-Update-Agent': 'DocumentationHub',
247
+
248
+ // GitHub-specific headers that might be whitelisted
249
+ 'X-GitHub-Request-Id': `dochub-${Date.now()}`,
250
+ 'X-GitHub-Media-Type': 'github.v3',
251
+
252
+ // Some Zscaler configurations respect npm/package manager user agents
253
+ 'User-Agent': `npm/8.0.0 node/${process.version} ${process.platform} ${process.arch} DocumentationHub/${app.getVersion()}`
254
+ };
255
+
256
+ // If we have a Zscaler API token (from environment), add it
257
+ const zscalerToken = process.env.ZSCALER_API_TOKEN || process.env.ZS_API_TOKEN;
258
+ if (zscalerToken) {
259
+ headers['X-Zscaler-API-Token'] = zscalerToken;
260
+ log.info('[ZscalerConfig] Added Zscaler API token to bypass headers');
261
+ }
262
+
263
+ // If we have a bypass code from IT department
264
+ const bypassCode = process.env.ZSCALER_BYPASS_CODE || process.env.CORPORATE_BYPASS_CODE;
265
+ if (bypassCode) {
266
+ headers['X-Bypass-Code'] = bypassCode;
267
+ log.info('[ZscalerConfig] Added corporate bypass code to headers');
268
+ }
269
+
270
+ return headers;
271
+ }
272
+
273
+ /**
274
+ * Check if Zscaler is causing certificate errors
275
+ */
276
+ public isZscalerError(error: any): boolean {
277
+ if (!error) return false;
278
+
279
+ const errorMessage = error.message?.toLowerCase() || '';
280
+ const errorCode = error.code || '';
281
+
282
+ const zscalerIndicators = [
283
+ 'zscaler',
284
+ 'unable to get local issuer certificate',
285
+ 'self signed certificate in certificate chain',
286
+ 'unable_to_get_issuer_cert_locally',
287
+ 'self_signed_cert_in_chain',
288
+ 'depth zero self signed cert',
289
+ 'certificate verify failed',
290
+ // Common with Zscaler
291
+ 'err_cert_authority_invalid',
292
+ 'err_cert_common_name_invalid'
293
+ ];
294
+
295
+ return zscalerIndicators.some(indicator =>
296
+ errorMessage.includes(indicator) || errorCode.toLowerCase().includes(indicator)
297
+ );
298
+ }
299
+
300
+ /**
301
+ * Get certificate content for injection
302
+ */
303
+ public getCertificateContent(): string | null {
304
+ return this.certificateContent;
305
+ }
306
+
307
+ /**
308
+ * Check if Zscaler is detected
309
+ */
310
+ public isDetected(): boolean {
311
+ return this.isZscalerDetected;
312
+ }
313
+
314
+ /**
315
+ * Get Zscaler certificate path
316
+ */
317
+ public getCertPath(): string | null {
318
+ return this.zscalerCertPath;
319
+ }
320
+
321
+ /**
322
+ * Create a combined certificate bundle
323
+ */
324
+ public async createCertBundle(): Promise<string | null> {
325
+ if (!this.certificateContent) {
326
+ return null;
327
+ }
328
+
329
+ try {
330
+ const tempDir = app.getPath('temp');
331
+ const bundlePath = path.join(tempDir, 'zscaler-cert-bundle.pem');
332
+
333
+ // Get system certificates if available
334
+ let systemCerts = '';
335
+ if (process.platform === 'win32') {
336
+ // On Windows, we might need to export system certs
337
+ try {
338
+ const { stdout } = await execAsync('certutil -store -silent Root');
339
+ // This would need more processing to extract actual certificates
340
+ log.info('[ZscalerConfig] System certificates available');
341
+ } catch (e) {
342
+ // Ignore
343
+ }
344
+ }
345
+
346
+ // Combine certificates
347
+ const bundle = this.certificateContent + '\n' + systemCerts;
348
+ // PEM files are text files, use UTF-8 encoding
349
+ fs.writeFileSync(bundlePath, bundle, 'utf-8');
350
+
351
+ log.info(` Created certificate bundle at: ${bundlePath}`);
352
+ return bundlePath;
353
+ } catch (error) {
354
+ log.error('[ZscalerConfig] Failed to create certificate bundle:', error);
355
+ return null;
356
+ }
357
+ }
358
+
359
+ /**
360
+ * Log Zscaler configuration for debugging
361
+ */
362
+ public logConfiguration(): void {
363
+ log.info('[ZscalerConfig] Configuration Summary:');
364
+ log.info(` - Zscaler Detected: ${this.isZscalerDetected}`);
365
+ log.info(` - Certificate Path: ${this.zscalerCertPath || 'Not found'}`);
366
+ log.info(` - Certificate Loaded: ${this.certificateContent ? 'Yes' : 'No'}`);
367
+ log.info(` - NODE_EXTRA_CA_CERTS: ${process.env.NODE_EXTRA_CA_CERTS || 'Not set'}`);
368
+ log.info(` - ZSCALER_BYPASS: ${process.env.ZSCALER_BYPASS || 'Not set'}`);
369
+
370
+ if (this.isZscalerDetected && !this.zscalerCertPath) {
371
+ log.info('[ZscalerConfig] WARNING: Zscaler detected but certificate not found!');
372
+ log.info('[ZscalerConfig] You may need to:');
373
+ log.info(' 1. Export Zscaler certificate from your browser');
374
+ log.info(' 2. Save it as C:\\Zscaler\\ZscalerRootCertificate.pem');
375
+ log.info(' 3. Or set ZSCALER_CERT_PATH environment variable');
376
+ }
377
+ }
378
+ }
379
+
380
+ // Export singleton instance
381
+ export const zscalerConfig = new ZscalerConfig();
@@ -0,0 +1,92 @@
1
+ import js from '@eslint/js';
2
+ import typescript from '@typescript-eslint/eslint-plugin';
3
+ import typescriptParser from '@typescript-eslint/parser';
4
+ import react from 'eslint-plugin-react';
5
+ import reactHooks from 'eslint-plugin-react-hooks';
6
+ import prettier from 'eslint-config-prettier';
7
+
8
+ export default [
9
+ {
10
+ ignores: [
11
+ 'dist/**',
12
+ 'build/**',
13
+ 'node_modules/**',
14
+ 'GH_Issues/scratchpads/**',
15
+ '*.min.js',
16
+ 'coverage/**',
17
+ ],
18
+ },
19
+ js.configs.recommended,
20
+ prettier,
21
+ {
22
+ files: ['**/*.{ts,tsx,js,jsx}'],
23
+ languageOptions: {
24
+ parser: typescriptParser,
25
+ parserOptions: {
26
+ ecmaVersion: 'latest',
27
+ sourceType: 'module',
28
+ ecmaFeatures: {
29
+ jsx: true,
30
+ },
31
+ },
32
+ globals: {
33
+ // Browser globals
34
+ window: 'readonly',
35
+ document: 'readonly',
36
+ navigator: 'readonly',
37
+ console: 'readonly',
38
+ setTimeout: 'readonly',
39
+ clearTimeout: 'readonly',
40
+ setInterval: 'readonly',
41
+ clearInterval: 'readonly',
42
+ requestAnimationFrame: 'readonly',
43
+ cancelAnimationFrame: 'readonly',
44
+ localStorage: 'readonly',
45
+ sessionStorage: 'readonly',
46
+ // Node globals
47
+ process: 'readonly',
48
+ Buffer: 'readonly',
49
+ __dirname: 'readonly',
50
+ __filename: 'readonly',
51
+ module: 'readonly',
52
+ require: 'readonly',
53
+ global: 'readonly',
54
+ },
55
+ },
56
+ plugins: {
57
+ '@typescript-eslint': typescript,
58
+ react: react,
59
+ 'react-hooks': reactHooks,
60
+ },
61
+ rules: {
62
+ // TypeScript rules
63
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
64
+ '@typescript-eslint/no-unused-vars': [
65
+ 'warn',
66
+ {
67
+ argsIgnorePattern: '^_',
68
+ varsIgnorePattern: '^_',
69
+ },
70
+ ],
71
+ '@typescript-eslint/no-explicit-any': 'warn',
72
+
73
+ // React rules
74
+ 'react/react-in-jsx-scope': 'off',
75
+ 'react/prop-types': 'off',
76
+ 'react/display-name': 'off',
77
+
78
+ // React Hooks rules
79
+ 'react-hooks/rules-of-hooks': 'error',
80
+ 'react-hooks/exhaustive-deps': 'warn',
81
+
82
+ // General rules
83
+ 'no-unused-vars': 'off', // Using TypeScript's no-unused-vars instead
84
+ 'no-undef': 'off', // TypeScript handles this
85
+ },
86
+ settings: {
87
+ react: {
88
+ version: 'detect',
89
+ },
90
+ },
91
+ },
92
+ ];
package/jest.config.js ADDED
@@ -0,0 +1,52 @@
1
+ /** @type {import('jest').Config} */
2
+ const config = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'jsdom',
5
+ roots: ['<rootDir>/src'],
6
+ moduleNameMapper: {
7
+ '^@/(.*)$': '<rootDir>/src/$1',
8
+ '^@components/(.*)$': '<rootDir>/src/components/$1',
9
+ '^@hooks/(.*)$': '<rootDir>/src/hooks/$1',
10
+ '^@utils/(.*)$': '<rootDir>/src/utils/$1',
11
+ '^@styles/(.*)$': '<rootDir>/src/styles/$1',
12
+ '^@pages/(.*)$': '<rootDir>/src/pages/$1',
13
+ '^@contexts/(.*)$': '<rootDir>/src/contexts/$1',
14
+ '\\.(css|less|scss|sass)$': '<rootDir>/src/__mocks__/styleMock.js',
15
+ '^p-limit$': '<rootDir>/src/__mocks__/p-limit.js',
16
+ },
17
+ setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
18
+ testMatch: ['**/__tests__/**/*.test.{ts,tsx}', '**/*.test.{ts,tsx}'],
19
+ transform: {
20
+ '^.+\\.tsx?$': [
21
+ 'ts-jest',
22
+ {
23
+ tsconfig: {
24
+ jsx: 'react-jsx',
25
+ esModuleInterop: true,
26
+ strict: true,
27
+ moduleResolution: 'node',
28
+ },
29
+ },
30
+ ],
31
+ },
32
+ transformIgnorePatterns: [
33
+ '/node_modules/(?!(p-limit|yocto-queue|lucide-react|framer-motion|@radix-ui|diff)/)',
34
+ ],
35
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
36
+ collectCoverageFrom: [
37
+ 'src/**/*.{ts,tsx}',
38
+ '!src/**/*.d.ts',
39
+ '!src/main.tsx',
40
+ '!src/__mocks__/**',
41
+ ],
42
+ coverageThreshold: {
43
+ global: {
44
+ branches: 50,
45
+ functions: 50,
46
+ lines: 50,
47
+ statements: 50,
48
+ },
49
+ },
50
+ };
51
+
52
+ module.exports = config;