@karmaniverous/jeeves-server 3.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/.env.local +13 -0
  2. package/.env.local.template +13 -0
  3. package/.tsbuildinfo +1 -0
  4. package/CHANGELOG.md +450 -0
  5. package/about.md +82 -0
  6. package/client/README.md +73 -0
  7. package/client/eslint.config.js +23 -0
  8. package/client/index.html +14 -0
  9. package/client/package-lock.json +5181 -0
  10. package/client/package.json +60 -0
  11. package/client/public/vite.svg +1 -0
  12. package/client/src/App.tsx +22 -0
  13. package/client/src/components/AccountMenu.tsx +167 -0
  14. package/client/src/components/ActionDropdown.tsx +120 -0
  15. package/client/src/components/CodeEditor.tsx +143 -0
  16. package/client/src/components/CodeViewer.tsx +113 -0
  17. package/client/src/components/ConfirmDialog.tsx +32 -0
  18. package/client/src/components/DirectoryRow.tsx +62 -0
  19. package/client/src/components/DirectoryTable.tsx +42 -0
  20. package/client/src/components/DownloadDropdown.tsx +116 -0
  21. package/client/src/components/DriveList.tsx +54 -0
  22. package/client/src/components/EmbeddedDiagramPanzoom.ts +28 -0
  23. package/client/src/components/FileContentView.tsx +155 -0
  24. package/client/src/components/InlineSvgPanzoom.ts +60 -0
  25. package/client/src/components/LazyDiagram.ts +93 -0
  26. package/client/src/components/LinkDropdown.tsx +134 -0
  27. package/client/src/components/MarkdownView.tsx +115 -0
  28. package/client/src/components/MermaidViewer.tsx +21 -0
  29. package/client/src/components/PlantUmlViewer.tsx +21 -0
  30. package/client/src/components/SearchModal.tsx +424 -0
  31. package/client/src/components/SvgViewer.tsx +107 -0
  32. package/client/src/components/TabBar.tsx +96 -0
  33. package/client/src/components/layout/Header.tsx +270 -0
  34. package/client/src/components/panzoom.ts +203 -0
  35. package/client/src/components/renderableUtils.ts +15 -0
  36. package/client/src/components/runner/JobTable.tsx +153 -0
  37. package/client/src/components/runner/RunHistory.tsx +140 -0
  38. package/client/src/components/runner/StatsBar.tsx +43 -0
  39. package/client/src/components/runner/StatusPill.tsx +27 -0
  40. package/client/src/components/runner/jobTableUtils.ts +65 -0
  41. package/client/src/components/scrollUtils.ts +39 -0
  42. package/client/src/components/ui/alert-dialog.tsx +107 -0
  43. package/client/src/components/ui/button.tsx +40 -0
  44. package/client/src/components/ui/dropdown-menu.tsx +79 -0
  45. package/client/src/components/ui/input.tsx +26 -0
  46. package/client/src/components/useActionState.ts +43 -0
  47. package/client/src/hooks/useFileBrowser.ts +102 -0
  48. package/client/src/hooks/useFileData.ts +78 -0
  49. package/client/src/hooks/useScrollAnchor.ts +70 -0
  50. package/client/src/hooks/useShareSettings.ts +22 -0
  51. package/client/src/hooks/useTopBar.ts +27 -0
  52. package/client/src/index.css +281 -0
  53. package/client/src/lib/AuthContext.ts +27 -0
  54. package/client/src/lib/api.ts +239 -0
  55. package/client/src/lib/auth.tsx +50 -0
  56. package/client/src/lib/codeBlockCm6.ts +129 -0
  57. package/client/src/lib/codeBlockCopy.ts +43 -0
  58. package/client/src/lib/codemirror.ts +77 -0
  59. package/client/src/lib/runner-api.ts +172 -0
  60. package/client/src/lib/svg.ts +50 -0
  61. package/client/src/lib/theme.ts +34 -0
  62. package/client/src/lib/utils.ts +6 -0
  63. package/client/src/main.tsx +11 -0
  64. package/client/src/pages/FileBrowser.tsx +135 -0
  65. package/client/src/pages/Home.tsx +46 -0
  66. package/client/src/pages/Runner.tsx +151 -0
  67. package/client/src/pages/RunnerJob.tsx +170 -0
  68. package/client/tsconfig.app.json +32 -0
  69. package/client/tsconfig.json +7 -0
  70. package/client/tsconfig.node.json +26 -0
  71. package/client/vite.config.ts +35 -0
  72. package/content/privacy.md +61 -0
  73. package/content/terms.md +41 -0
  74. package/dist/client/assets/CodeEditor-0XHVI8Nu.js +1 -0
  75. package/dist/client/assets/CodeViewer-CykMVsfX.js +1 -0
  76. package/dist/client/assets/index--MBieNJA.js +1 -0
  77. package/dist/client/assets/index-BENeXQI_.js +1 -0
  78. package/dist/client/assets/index-BbBpoOxz.js +1 -0
  79. package/dist/client/assets/index-BdV9g5AM.js +6 -0
  80. package/dist/client/assets/index-BjAilRri.js +2 -0
  81. package/dist/client/assets/index-BqbhWo2I.js +3 -0
  82. package/dist/client/assets/index-CVbycZ0H.js +1 -0
  83. package/dist/client/assets/index-Cs5oz2oJ.js +5 -0
  84. package/dist/client/assets/index-D8KZVveX.js +1 -0
  85. package/dist/client/assets/index-DC4HMHxY.js +13 -0
  86. package/dist/client/assets/index-DbMebkkd.css +1 -0
  87. package/dist/client/assets/index-DcY2RXqX.js +1 -0
  88. package/dist/client/assets/index-Duy-tZYV.js +1 -0
  89. package/dist/client/assets/index-Dw7rDFmE.js +7 -0
  90. package/dist/client/assets/index-FlCUvrjv.js +2 -0
  91. package/dist/client/assets/index-K6OVmfhg.js +1 -0
  92. package/dist/client/assets/index-LjwgzZ7F.js +62 -0
  93. package/dist/client/assets/index-MLwyFRN0.js +1 -0
  94. package/dist/client/assets/index-OpqBpSjn.js +1 -0
  95. package/dist/client/assets/index-SsHei0HE.js +1 -0
  96. package/dist/client/assets/index-uQa2yckk.js +1 -0
  97. package/dist/client/assets/index-udkXoIER.js +1 -0
  98. package/dist/client/index.html +15 -0
  99. package/dist/client/vite.svg +1 -0
  100. package/dist/src/auth/google.js +57 -0
  101. package/dist/src/auth/keys.js +185 -0
  102. package/dist/src/auth/resolve.js +102 -0
  103. package/dist/src/auth/session.js +57 -0
  104. package/dist/src/cli/commands/config.js +100 -0
  105. package/dist/src/cli/commands/config.test.js +84 -0
  106. package/dist/src/cli/commands/service.js +93 -0
  107. package/dist/src/cli/commands/start.js +24 -0
  108. package/dist/src/cli/index.js +20 -0
  109. package/dist/src/config/index.js +90 -0
  110. package/dist/src/config/loadConfig.test.js +127 -0
  111. package/dist/src/config/resolve.js +134 -0
  112. package/dist/src/config/resolve.test.js +148 -0
  113. package/dist/src/config/schema.js +159 -0
  114. package/dist/src/config/substituteEnvVars.js +45 -0
  115. package/dist/src/config/substituteEnvVars.test.js +51 -0
  116. package/dist/src/config/types.js +5 -0
  117. package/dist/src/routes/api/auth-status.js +56 -0
  118. package/dist/src/routes/api/diagrams.js +35 -0
  119. package/dist/src/routes/api/directory.js +93 -0
  120. package/dist/src/routes/api/drives.js +15 -0
  121. package/dist/src/routes/api/export.js +218 -0
  122. package/dist/src/routes/api/fileContent.js +286 -0
  123. package/dist/src/routes/api/index.js +33 -0
  124. package/dist/src/routes/api/linkInfo.js +71 -0
  125. package/dist/src/routes/api/linkInfo.test.js +104 -0
  126. package/dist/src/routes/api/middleware.js +117 -0
  127. package/dist/src/routes/api/raw.js +38 -0
  128. package/dist/src/routes/api/runner.js +59 -0
  129. package/dist/src/routes/api/search.js +236 -0
  130. package/dist/src/routes/api/sharing.js +203 -0
  131. package/dist/src/routes/api/status.js +68 -0
  132. package/dist/src/routes/api/status.test.js +62 -0
  133. package/dist/src/routes/auth.js +99 -0
  134. package/dist/src/routes/event.js +77 -0
  135. package/dist/src/routes/event.test.js +206 -0
  136. package/dist/src/routes/health.js +10 -0
  137. package/dist/src/routes/keys.js +129 -0
  138. package/dist/src/routes/path/index.js +17 -0
  139. package/dist/src/routes/static.js +30 -0
  140. package/dist/src/server.js +90 -0
  141. package/dist/src/services/deepShareLinks.js +163 -0
  142. package/dist/src/services/diagramCache.js +104 -0
  143. package/dist/src/services/embeddedDiagrams.js +136 -0
  144. package/dist/src/services/eventLog.js +55 -0
  145. package/dist/src/services/eventLog.test.js +113 -0
  146. package/dist/src/services/eventQueue.js +154 -0
  147. package/dist/src/services/eventQueue.test.js +104 -0
  148. package/dist/src/services/export.js +220 -0
  149. package/dist/src/services/exportCache.js +196 -0
  150. package/dist/src/services/markdown.js +147 -0
  151. package/dist/src/services/mermaid.js +97 -0
  152. package/dist/src/services/plantuml.js +145 -0
  153. package/dist/src/services/puppeteer.js +156 -0
  154. package/dist/src/util/breadcrumbs.js +22 -0
  155. package/dist/src/util/crypto.js +56 -0
  156. package/dist/src/util/crypto.test.js +99 -0
  157. package/dist/src/util/fileDetection.js +66 -0
  158. package/dist/src/util/fileDetection.test.js +89 -0
  159. package/dist/src/util/formatters.js +43 -0
  160. package/dist/src/util/formatters.test.js +83 -0
  161. package/dist/src/util/packageVersion.js +25 -0
  162. package/dist/src/util/platform.js +148 -0
  163. package/dist/src/util/state.js +46 -0
  164. package/dist/vitest.config.js +12 -0
  165. package/favicon.svg +3 -0
  166. package/guides/access-decision-flow.mmd +24 -0
  167. package/guides/access-decision-flow.svg +1 -0
  168. package/guides/api-integration.md +236 -0
  169. package/guides/deployment.md +287 -0
  170. package/guides/event-gateway.md +204 -0
  171. package/guides/event-gateway.mmd +17 -0
  172. package/guides/event-gateway.svg +1 -0
  173. package/guides/exports.md +239 -0
  174. package/guides/setup.md +313 -0
  175. package/guides/sharing.md +204 -0
  176. package/jeeves-server.config.template.json +25 -0
  177. package/package.json +124 -0
  178. package/scripts/download-plantuml.js +70 -0
  179. package/src/auth/google.ts +93 -0
  180. package/src/auth/keys.ts +252 -0
  181. package/src/auth/resolve.ts +157 -0
  182. package/src/auth/session.ts +77 -0
  183. package/src/cli/commands/config.test.ts +107 -0
  184. package/src/cli/commands/config.ts +113 -0
  185. package/src/cli/commands/service.ts +129 -0
  186. package/src/cli/commands/start.ts +27 -0
  187. package/src/cli/index.ts +25 -0
  188. package/src/config/index.ts +113 -0
  189. package/src/config/loadConfig.test.ts +155 -0
  190. package/src/config/resolve.test.ts +192 -0
  191. package/src/config/resolve.ts +173 -0
  192. package/src/config/schema.ts +179 -0
  193. package/src/config/substituteEnvVars.test.ts +64 -0
  194. package/src/config/substituteEnvVars.ts +52 -0
  195. package/src/config/types.ts +129 -0
  196. package/src/routes/api/auth-status.ts +85 -0
  197. package/src/routes/api/diagrams.ts +53 -0
  198. package/src/routes/api/directory.ts +123 -0
  199. package/src/routes/api/drives.ts +23 -0
  200. package/src/routes/api/export.ts +314 -0
  201. package/src/routes/api/fileContent.ts +414 -0
  202. package/src/routes/api/index.ts +37 -0
  203. package/src/routes/api/linkInfo.test.ts +132 -0
  204. package/src/routes/api/linkInfo.ts +83 -0
  205. package/src/routes/api/middleware.ts +156 -0
  206. package/src/routes/api/raw.ts +54 -0
  207. package/src/routes/api/runner.ts +107 -0
  208. package/src/routes/api/search.ts +321 -0
  209. package/src/routes/api/sharing.ts +259 -0
  210. package/src/routes/api/status.test.ts +72 -0
  211. package/src/routes/api/status.ts +82 -0
  212. package/src/routes/auth.ts +143 -0
  213. package/src/routes/event.test.ts +248 -0
  214. package/src/routes/event.ts +109 -0
  215. package/src/routes/health.ts +13 -0
  216. package/src/routes/keys.ts +192 -0
  217. package/src/routes/path/index.ts +24 -0
  218. package/src/routes/static.ts +54 -0
  219. package/src/server.ts +104 -0
  220. package/src/services/deepShareLinks.ts +203 -0
  221. package/src/services/diagramCache.ts +128 -0
  222. package/src/services/embeddedDiagrams.ts +168 -0
  223. package/src/services/eventLog.test.ts +144 -0
  224. package/src/services/eventLog.ts +68 -0
  225. package/src/services/eventQueue.test.ts +127 -0
  226. package/src/services/eventQueue.ts +196 -0
  227. package/src/services/export.ts +267 -0
  228. package/src/services/exportCache.ts +216 -0
  229. package/src/services/markdown.ts +189 -0
  230. package/src/services/mermaid.ts +113 -0
  231. package/src/services/plantuml.ts +172 -0
  232. package/src/services/puppeteer.ts +188 -0
  233. package/src/types/fastify.d.ts +13 -0
  234. package/src/types/jsonmap.d.ts +10 -0
  235. package/src/types/plantuml-encoder.d.ts +4 -0
  236. package/src/util/breadcrumbs.ts +33 -0
  237. package/src/util/crypto.test.ts +132 -0
  238. package/src/util/crypto.ts +79 -0
  239. package/src/util/fileDetection.test.ts +115 -0
  240. package/src/util/fileDetection.ts +70 -0
  241. package/src/util/formatters.test.ts +105 -0
  242. package/src/util/formatters.ts +44 -0
  243. package/src/util/packageVersion.ts +30 -0
  244. package/src/util/platform.ts +178 -0
  245. package/src/util/state.ts +55 -0
  246. package/test-docs/diagram-retry-test.md +18 -0
  247. package/test-docs/embedded-diagrams.md +52 -0
  248. package/test-docs/lazy-diagrams-test.md +333 -0
  249. package/test-docs/page-a.md +7 -0
  250. package/test-docs/page-b.md +7 -0
  251. package/test-docs/page-c.md +7 -0
  252. package/test-docs/sub/page-d.md +7 -0
  253. package/test-docs/test-diagram.puml +13 -0
  254. package/test-docs/validate-deep-share.js +318 -0
  255. package/tsconfig.json +37 -0
  256. package/tsdoc.json +13 -0
  257. package/vendor/.plantuml-version +1 -0
  258. package/vendor/plantuml.jar +0 -0
  259. package/vitest.config.js +12 -0
  260. package/vitest.config.ts +13 -0
@@ -0,0 +1,239 @@
1
+ # Exporting & Downloads
2
+
3
+ Jeeves Server can export files as PDF, DOCX, or ZIP — turning Markdown into business-ready documents with one click.
4
+
5
+ ## Export Types
6
+
7
+ | Format | Available For | How It Works |
8
+ |--------|--------------|--------------|
9
+ | **PDF** | Markdown, Mermaid, PlantUML | Puppeteer (Markdown) or diagram renderer (Mermaid/PlantUML) |
10
+ | **DOCX** | Markdown files | HTML converted via `@turbodocx/html-to-docx` |
11
+ | **SVG** | Mermaid (`.mmd`), PlantUML (`.puml`, `.pu`, `.plantuml`) | Rendered via Mermaid CLI or PlantUML jar/server |
12
+ | **PNG** | Mermaid, PlantUML | Rendered via Mermaid CLI or PlantUML jar/server |
13
+ | **EPS** | PlantUML (jar only) | Vector export via PlantUML jar |
14
+ | **ZIP** | Directories | Entire directory tree compressed via [`archiver`](https://github.com/archiverjs/node-archiver) |
15
+ | **Raw** | Any file | Direct file download |
16
+
17
+ ## Using Exports
18
+
19
+ ### From the UI
20
+
21
+ The **Download dropdown** (⬇️ icon) in the header shows available export options based on the current file type. Click an option and the file downloads directly — a spinner shows during generation, replaced by a checkmark on completion.
22
+
23
+ ### Via URL Parameters
24
+
25
+ Append to any file URL:
26
+
27
+ ```
28
+ # PDF export
29
+ /browse/d/docs/design.md?export=pdf
30
+
31
+ # DOCX export
32
+ /browse/d/docs/design.md?export=docx
33
+
34
+ # Raw file download
35
+ /browse/d/docs/design.md?raw=1
36
+ ```
37
+
38
+ These work with both insider keys (`?key=<insider-key>&export=pdf`) and outsider share links.
39
+
40
+ ### Programmatic Access
41
+
42
+ ```bash
43
+ # Download PDF via curl
44
+ curl -o design.pdf "https://jeeves.example.com/path/d/docs/design.md?key=<key>&export=pdf"
45
+
46
+ # Download DOCX
47
+ curl -o design.docx "https://jeeves.example.com/path/d/docs/design.md?key=<key>&export=docx"
48
+
49
+ # Download raw file
50
+ curl -o design.md "https://jeeves.example.com/path/d/docs/design.md?key=<key>&raw=1"
51
+ ```
52
+
53
+ ## PDF Export
54
+
55
+ PDF generation uses [**Puppeteer**](https://github.com/puppeteer/puppeteer) with your installed Chrome/Chromium. The server:
56
+
57
+ 1. Launches headless Chrome
58
+ 2. Loads the rendered markdown page (authenticating with the `_internal` key)
59
+ 3. Prints to PDF with print-quality settings
60
+ 4. Returns the PDF as a download
61
+
62
+ ### Requirements
63
+
64
+ - **Chrome/Chromium** must be installed on the server
65
+ - **`chromePath`** must point to the executable in `jeeves.config.ts`
66
+ - **`_internal` key** must be configured (Puppeteer uses it to authenticate)
67
+
68
+ ```typescript
69
+ chromePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
70
+ keys: {
71
+ _internal: 'random-seed-string', // Required for PDF/DOCX export
72
+ },
73
+ ```
74
+
75
+ ### What you see is what you get
76
+
77
+ PDFs render from the same HTML as the browser view, but:
78
+ - **Prose width setting is ignored** — exports always use full width
79
+ - **Dark mode is ignored** — exports always render in light mode
80
+ - **TOC sidebar is excluded** — the document stands alone
81
+ - **Code blocks retain syntax highlighting** — colors print correctly
82
+
83
+ ### Troubleshooting
84
+
85
+ **"Export failed" error:**
86
+ - Verify `chromePath` points to a valid Chrome/Chromium executable
87
+ - Ensure the `_internal` key is configured in `keys`
88
+ - Check server logs for Puppeteer errors
89
+
90
+ **Blank or login page in PDF:**
91
+ - The `_internal` key's derived insider key must be valid
92
+ - Verify with: `curl -s "http://localhost:<port>/insider-key" -H "X-API-Key: <_internal-seed>"`
93
+
94
+ **Timeout on large documents:**
95
+ - Large markdown files with many code blocks or diagrams take longer to render
96
+ - The server has a default timeout; very large documents may need optimization
97
+
98
+ ## DOCX Export
99
+
100
+ DOCX generation converts the rendered HTML to a Word document using [`@turbodocx/html-to-docx`](https://github.com/nickmessing/turbodocx). This happens server-side without Chrome.
101
+
102
+ DOCX exports:
103
+ - Preserve headings, tables, lists, and basic formatting
104
+ - Include code blocks (without syntax highlighting colors)
105
+ - Embed images as inline content
106
+ - Work independently of the `_internal` key (no Puppeteer needed)
107
+
108
+ ## Mermaid Export
109
+
110
+ Mermaid diagrams (`.mmd` files) can be exported as SVG, PNG, or PDF via the [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli) (`mmdc`).
111
+
112
+ ### Requirements
113
+
114
+ - **Mermaid CLI** must be installed (via npm)
115
+ - **`mermaidCliPath`** must point to the `mmdc` binary in `jeeves.config.ts`
116
+ - **Puppeteer/Chrome** is required by Mermaid CLI for rendering
117
+
118
+ ```typescript
119
+ mermaidCliPath: '/usr/local/bin/mmdc',
120
+ ```
121
+
122
+ ### Export endpoint
123
+
124
+ ```
125
+ GET /api/mermaid-export/<path>?format=svg|png|pdf
126
+ ```
127
+
128
+ ## PlantUML Export
129
+
130
+ PlantUML files (`.puml`, `.pu`, `.plantuml`) can be exported as SVG, PNG, PDF, or EPS.
131
+
132
+ ### Rendering pipeline
133
+
134
+ PlantUML uses a **fallback rendering pipeline** — each method is tried in order until one succeeds:
135
+
136
+ 1. **Local Java jar** — fastest, supports `!include` directives for complex diagrams with shared libraries. Requires Java and the PlantUML jar.
137
+ 2. **Configured PlantUML servers** — self-hosted or private PlantUML server instances, tried in order.
138
+ 3. **Public community server** (`plantuml.com`) — always appended as the last resort. Cannot resolve `!include` directives.
139
+
140
+ ### Configuration
141
+
142
+ ```typescript
143
+ plantuml: {
144
+ jarPath: '/opt/plantuml/plantuml.jar', // Local jar path (optional)
145
+ javaPath: '/usr/bin/java', // Java binary (optional, defaults to 'java')
146
+ servers: ['https://internal.plantuml.example.com/plantuml'], // Private servers (optional)
147
+ },
148
+ ```
149
+
150
+ If `plantuml` is omitted entirely, only the public community server is used.
151
+
152
+ ### Export formats
153
+
154
+ | Format | Jar | Server |
155
+ |--------|-----|--------|
156
+ | SVG | ✅ | ✅ |
157
+ | PNG | ✅ | ✅ |
158
+ | PDF | ✅ | ❌ |
159
+ | EPS | ✅ | ❌ |
160
+
161
+ ### Export endpoint
162
+
163
+ ```
164
+ GET /api/plantuml-export/<path>?format=svg|png|pdf|eps
165
+ ```
166
+
167
+ ### `!include` support
168
+
169
+ Only the **local jar** method resolves `!include` directives. If your diagrams reference shared PlantUML libraries (e.g., AWS icons, company style files), you must configure `jarPath`. The jar runs with `cwd` set to the diagram's parent directory, so relative includes resolve naturally.
170
+
171
+ ## Embedded Diagrams in Markdown
172
+
173
+ Markdown files can contain **inline diagram source** in fenced code blocks. Following the [GitHub convention](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/), code blocks tagged `mermaid` or `plantuml` (also `puml`) are rendered as inline SVG diagrams when the page is displayed.
174
+
175
+ ````markdown
176
+ ```mermaid
177
+ graph TD
178
+ A[Start] --> B{Decision}
179
+ B -->|Yes| C[Do it]
180
+ B -->|No| D[Skip]
181
+ ```
182
+
183
+ ```plantuml
184
+ @startuml
185
+ Alice -> Bob: Hello
186
+ Bob --> Alice: Hi!
187
+ @enduml
188
+ ```
189
+ ````
190
+
191
+ ### How it works
192
+
193
+ Diagram blocks are detected during markdown parsing, replaced with placeholders, and rendered server-side after HTML generation:
194
+ - **Mermaid** — rendered via Mermaid CLI (`mmdc`) to SVG
195
+ - **PlantUML** — rendered via the same fallback pipeline as `.puml` files (jar → servers → community)
196
+
197
+ If rendering fails, the source code is displayed with a small error label.
198
+
199
+ ### Showing source instead of rendering
200
+
201
+ To display diagram source as a code block (without rendering), use a different language hint:
202
+
203
+ ````markdown
204
+ ```text
205
+ graph TD
206
+ A --> B
207
+ ```
208
+ ````
209
+
210
+ ### PDF/DOCX export
211
+
212
+ Embedded diagrams appear in PDF and DOCX exports as rendered SVGs — what you see in the browser is what you get in the export.
213
+
214
+ ## ZIP Export
215
+
216
+ Directories can be downloaded as ZIP archives. The header shows a ZIP download option when viewing a directory.
217
+
218
+ ### Size limit
219
+
220
+ The `maxZipSizeMb` config setting (default: 100 MB) prevents accidentally zipping enormous directories:
221
+
222
+ ```typescript
223
+ maxZipSizeMb: 100, // Refuse ZIP for directories larger than this
224
+ ```
225
+
226
+ When the total directory size exceeds this limit, the ZIP option is disabled with a message explaining why.
227
+
228
+ ### What's included
229
+
230
+ The ZIP contains the entire directory tree — all files and subdirectories. No files are excluded.
231
+
232
+ ## Export for Outsiders
233
+
234
+ Outsiders (people using share links) can also export files:
235
+ - **PDF and DOCX** exports work on shared markdown files
236
+ - **Raw download** works on any shared file
237
+ - **ZIP** works on shared directories (within the size limit)
238
+
239
+ The share link's authentication covers the export — no additional credentials needed.
@@ -0,0 +1,313 @@
1
+ # Setup & Configuration
2
+
3
+ ## Prerequisites
4
+
5
+ - **Node.js** ≥ 18
6
+ - **Chrome or Chromium** — required for PDF export (Puppeteer uses it headlessly)
7
+ - **A domain or IP** where the server will be accessible (for Google OAuth callbacks)
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ git clone https://github.com/karmaniverous/jeeves-server.git
13
+ cd jeeves-server
14
+ npm install
15
+ ```
16
+
17
+ ## Configuration
18
+
19
+ Jeeves Server uses a **TypeScript configuration file** validated at startup by a [Zod](https://github.com/colinhacks/zod) schema. The schema at `src/config/schema.ts` is the single source of truth — all types are derived from it.
20
+
21
+ ### Create your config
22
+
23
+ ```bash
24
+ cp jeeves.config.template.ts jeeves.config.ts
25
+ ```
26
+
27
+ Edit `jeeves.config.ts` with your values. This file is **gitignored** — it contains secrets and is never committed.
28
+
29
+ ### Config structure
30
+
31
+ ```typescript
32
+ import type { JeevesConfig } from './src/config/schema.js';
33
+
34
+ export default {
35
+ port: 1934,
36
+ chromePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
37
+ auth: { ... },
38
+ insiders: { ... },
39
+ keys: { ... },
40
+ events: { ... },
41
+ } satisfies JeevesConfig;
42
+ ```
43
+
44
+ The `satisfies` keyword gives you type checking without losing literal types — your editor will autocomplete and validate as you type.
45
+
46
+ ### Platform-specific settings
47
+
48
+ **Windows** — drives are auto-discovered; no `roots` config needed:
49
+ ```typescript
50
+ chromePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
51
+ ```
52
+
53
+ **Linux** — configure filesystem roots for the file browser:
54
+ ```typescript
55
+ chromePath: '/usr/bin/chromium-browser',
56
+ roots: {
57
+ home: '/home',
58
+ projects: '/opt/projects',
59
+ },
60
+ mermaidCliPath: '/opt/mermaid-cli', // optional
61
+ plantuml: { // optional
62
+ jarPath: '/opt/plantuml/plantuml.jar',
63
+ javaPath: '/usr/bin/java', // defaults to 'java' on PATH
64
+ servers: [], // private servers; community server always appended
65
+ },
66
+ ```
67
+
68
+ On Windows, `roots` is ignored. On Linux, if omitted, it defaults to `{ root: '/' }`.
69
+
70
+ ### Config is immutable at runtime
71
+
72
+ Once the server starts, the config is loaded once and never written to. Mutable state (like auto-generated insider keys) lives in a separate `state.json` file that the server manages itself.
73
+
74
+ ---
75
+
76
+ ## Authentication Modes
77
+
78
+ Jeeves Server supports two authentication methods, configured via `auth.modes`:
79
+
80
+ ```typescript
81
+ auth: {
82
+ modes: ['google', 'keys'], // Active modes, in priority order
83
+ // ...
84
+ }
85
+ ```
86
+
87
+ You can enable one or both. The order matters — modes are checked in the order listed.
88
+
89
+ ### Google OAuth (`'google'`)
90
+
91
+ **Best for:** Teams where insiders log in via browser.
92
+
93
+ Users authenticate with their Google account. The server checks their email against the `insiders` map to determine access.
94
+
95
+ **Requirements when enabled:**
96
+ - `auth.google.clientId` and `auth.google.clientSecret` — from [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
97
+ - `auth.sessionSecret` — a random string for signing session cookies
98
+ - At least one entry in `insiders`
99
+
100
+ **Google Cloud setup:**
101
+ 1. Create a project (or use an existing one)
102
+ 2. Go to **APIs & Services → Credentials → Create Credentials → OAuth client ID**
103
+ 3. Application type: **Web application**
104
+ 4. Authorized redirect URI: `https://your-domain.com/auth/google/callback`
105
+ 5. Copy the client ID and client secret into your config
106
+
107
+ **Session secret generation:**
108
+ ```bash
109
+ node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
110
+ ```
111
+
112
+ ### Key-Based Auth (`'keys'`)
113
+
114
+ **Best for:** Headless access, bot integrations, simple setups without Google.
115
+
116
+ Users authenticate by appending `?key=<value>` to any URL. The server derives keys from configured seeds using HMAC-SHA256 and checks the provided key against all known derived keys.
117
+
118
+ **Requirements when enabled:**
119
+ - At least one entry in `keys`
120
+
121
+ **How keys work:** You configure a **seed** (a random secret string). The server derives the actual insider key from it via HMAC. You never put the derived key in the config — only the seed. To get the derived key for use in URLs:
122
+
123
+ ```bash
124
+ # Via the API (requires X-API-Key header with any seed)
125
+ curl -H "X-API-Key: <seed>" https://your-domain.com/insider-key
126
+ ```
127
+
128
+ ### Both Modes Together
129
+
130
+ ```typescript
131
+ auth: {
132
+ modes: ['keys', 'google'], // Keys checked first
133
+ }
134
+ ```
135
+
136
+ When both are active:
137
+ - Browser users can log in with Google for a session-based experience
138
+ - Bots and scripts can use `?key=` for stateless access
139
+ - Both methods work on every endpoint
140
+
141
+ ### Choosing a Mode
142
+
143
+ | Scenario | Recommended |
144
+ |----------|-------------|
145
+ | Team of humans accessing via browser | `['google']` |
146
+ | Bot/script access only | `['keys']` |
147
+ | Humans + bots on the same server | `['google', 'keys']` |
148
+ | Quick local setup, no Google credentials | `['keys']` |
149
+
150
+ ---
151
+
152
+ ## Insiders
153
+
154
+ The `insiders` map defines **who** has full browsing access. Each entry is an email address with optional path scopes:
155
+
156
+ ```typescript
157
+ insiders: {
158
+ // Full access
159
+ 'alice@example.com': {},
160
+
161
+ // Restricted to specific paths (allow-only)
162
+ 'contractor@example.com': {
163
+ scopes: ['/d/projects/client-x/*'],
164
+ },
165
+
166
+ // Broad access with cutouts (allow/deny)
167
+ 'team-member@example.com': {
168
+ scopes: {
169
+ allow: ['/d/*'],
170
+ deny: ['/d/secrets/*', '/d/.private/*'],
171
+ },
172
+ },
173
+ },
174
+ ```
175
+
176
+ With Google auth, insiders log in via OAuth and the server checks their email. With key auth, each insider gets a derived URL key.
177
+
178
+ See the [Insiders, Outsiders & Sharing](sharing.md) guide for the full access model.
179
+
180
+ ---
181
+
182
+ ## Keys
183
+
184
+ The `keys` map defines **named API keys** for machine access:
185
+
186
+ ```typescript
187
+ keys: {
188
+ // Unscoped — full access to all paths
189
+ primary: 'a-random-64-char-hex-string',
190
+
191
+ // Scoped — restricted to specific paths
192
+ 'webhook-notion': {
193
+ key: 'another-random-hex-string',
194
+ scopes: ['/event'],
195
+ },
196
+
197
+ // Reserved: internal server operations (Puppeteer export)
198
+ _internal: 'yet-another-random-hex-string',
199
+ },
200
+ ```
201
+
202
+ **Generate seeds with:**
203
+ ```bash
204
+ node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
205
+ ```
206
+
207
+ ### The `_internal` key
208
+
209
+ The `_internal` key is reserved for the server's own use — specifically, Puppeteer uses it to authenticate when rendering PDFs and DOCX files. It **must not** have scopes (enforced by the schema).
210
+
211
+ If you don't configure `_internal`, PDF/DOCX export will not work.
212
+
213
+ ### Key names
214
+
215
+ Key names are used for logging and identification. Choose meaningful names: `primary`, `webhook-notion`, `ci-bot`, etc.
216
+
217
+ ---
218
+
219
+ ## Event Gateway
220
+
221
+ The event gateway receives webhooks at `POST /event`, validates them against JSON Schema rules, and dispatches matched events to shell commands via a durable JSONL queue.
222
+
223
+ ```typescript
224
+ events: {
225
+ 'notion-page-update': {
226
+ // JSON Schema to match against incoming body
227
+ schema: {
228
+ type: 'object',
229
+ properties: { type: { const: 'page.content_updated' } },
230
+ required: ['type'],
231
+ },
232
+ // Command to execute when matched
233
+ cmd: 'node /path/to/handler.js',
234
+ // Optional: transform body before passing to command
235
+ map: {
236
+ pageId: { '$': { method: '$.lib._.get', params: ['$.input', 'data.page_id'] } },
237
+ },
238
+ // Optional: override default timeout
239
+ timeoutMs: 60000,
240
+ },
241
+ },
242
+ ```
243
+
244
+ Webhook callers authenticate with a scoped key:
245
+ ```bash
246
+ curl -X POST "https://your-domain.com/event?key=<webhook-key>" \
247
+ -H "Content-Type: application/json" \
248
+ -d '{"type": "page.content_updated", "data": {"page_id": "abc123"}}'
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Building
254
+
255
+ ```bash
256
+ # Full build (server TypeScript + React client)
257
+ npm run build # Compiles server → dist/
258
+ cd client && npx vite build --outDir ../dist/client && cd .. # Builds React SPA → dist/client/
259
+ ```
260
+
261
+ > ⚠️ `npm run build` deletes the entire `dist/` directory (including `dist/client/`). Always rebuild the client after the server.
262
+
263
+ ---
264
+
265
+ ## Running
266
+
267
+ ```bash
268
+ node dist/server.js
269
+ ```
270
+
271
+ ### As a Windows service
272
+
273
+ ```bash
274
+ nssm install JeevesServer "node" "/path/to/dist/server.js"
275
+ nssm start JeevesServer
276
+ ```
277
+
278
+ ### Health check
279
+
280
+ ```
281
+ GET /health
282
+ ```
283
+
284
+ Returns `200 OK` with no authentication required.
285
+
286
+ ---
287
+
288
+ ## File Layout
289
+
290
+ ```
291
+ jeeves-server/
292
+ ├── jeeves.config.ts # Your config (gitignored)
293
+ ├── jeeves.config.template.ts # Config template (committed)
294
+ ├── state.json # Runtime state (gitignored, auto-managed)
295
+ ├── src/ # Server source (TypeScript)
296
+ │ ├── config/
297
+ │ │ ├── schema.ts # Zod schema (source of truth)
298
+ │ │ ├── index.ts # Config loader (jiti for TS)
299
+ │ │ └── types.ts # Runtime types
300
+ │ ├── auth/ # Google OAuth + key verification
301
+ │ ├── routes/ # Fastify route handlers
302
+ │ ├── services/ # Export, markdown, event queue
303
+ │ └── server.ts # Entry point
304
+ ├── client/ # React SPA source
305
+ │ └── src/
306
+ │ ├── pages/ # FileBrowser, FileViewer, About
307
+ │ ├── components/ # Header, dropdowns, viewers
308
+ │ └── lib/ # API client, auth, theme
309
+ ├── dist/ # Compiled output (gitignored)
310
+ │ ├── server.js # Compiled server
311
+ │ └── client/ # Built React SPA
312
+ └── guides/ # Documentation
313
+ ```