living-documentation 1.4.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -3
- package/dist/src/frontend/index.html +149 -10
- package/dist/src/routes/documents.d.ts.map +1 -1
- package/dist/src/routes/documents.js +62 -13
- package/dist/src/routes/documents.js.map +1 -1
- package/dist/src/routes/images.d.ts +3 -0
- package/dist/src/routes/images.d.ts.map +1 -0
- package/dist/src/routes/images.js +42 -0
- package/dist/src/routes/images.js.map +1 -0
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +5 -1
- package/dist/src/server.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ No cloud, no database, no build step — just point it at a folder of `.md` file
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **Sidebar** grouped by category, sorted by
|
|
13
|
+
- **Sidebar** grouped by category, sorted alphabetically by full filename
|
|
14
14
|
- **General section** — always first, always expanded; holds uncategorized docs and extra files
|
|
15
15
|
- **Extra files** — include Markdown files from outside the docs folder (e.g. `README.md`, `CLAUDE.md`)
|
|
16
16
|
- **Full-text search** — instant filter + server-side content search
|
|
@@ -19,6 +19,8 @@ No cloud, no database, no build step — just point it at a folder of `.md` file
|
|
|
19
19
|
- **Export to PDF** — print-friendly layout via `window.print()`
|
|
20
20
|
- **Deep links** — share a direct URL to any document (`?doc=…`)
|
|
21
21
|
- **Admin panel** — configure title, theme, filename pattern, and extra files in the browser
|
|
22
|
+
- **Inline editing** — edit any document directly in the browser, saves to disk instantly
|
|
23
|
+
- **Image paste** — paste an image from clipboard in the editor; auto-uploaded and inserted as Markdown
|
|
22
24
|
- **Zero frontend build** — Tailwind and highlight.js loaded from CDN
|
|
23
25
|
|
|
24
26
|
---
|
|
@@ -108,6 +110,8 @@ YYYY_MM_DD_[Category]_title_words.md
|
|
|
108
110
|
|
|
109
111
|
Files that don't match the pattern are still shown — they appear under **General** with the filename as the title.
|
|
110
112
|
|
|
113
|
+
The pattern is **configurable** in the Admin panel. Token order is respected — `[Category]_YYYY_MM_DD_title` is valid. `[Category]` must appear exactly once.
|
|
114
|
+
|
|
111
115
|
---
|
|
112
116
|
|
|
113
117
|
## Config file
|
|
@@ -153,9 +157,10 @@ living-documentation/
|
|
|
153
157
|
├── src/
|
|
154
158
|
│ ├── server.ts Express app
|
|
155
159
|
│ ├── routes/
|
|
156
|
-
│ │ ├── documents.ts Documents API
|
|
160
|
+
│ │ ├── documents.ts Documents API (list, search, read, write)
|
|
157
161
|
│ │ ├── config.ts Config API
|
|
158
|
-
│ │
|
|
162
|
+
│ │ ├── browse.ts Filesystem browser API
|
|
163
|
+
│ │ └── images.ts Image upload API
|
|
159
164
|
│ ├── lib/
|
|
160
165
|
│ │ ├── parser.ts Filename parser
|
|
161
166
|
│ │ └── config.ts Config management
|
|
@@ -176,10 +181,12 @@ living-documentation/
|
|
|
176
181
|
| ------ | -------------------------- | ------------------------------------------------------------------ |
|
|
177
182
|
| `GET` | `/api/documents` | List all documents with metadata (includes extra files) |
|
|
178
183
|
| `GET` | `/api/documents/:id` | Get document content + rendered HTML |
|
|
184
|
+
| `PUT` | `/api/documents/:id` | Save document content to disk |
|
|
179
185
|
| `GET` | `/api/documents/search?q=` | Full-text search |
|
|
180
186
|
| `GET` | `/api/config` | Read config |
|
|
181
187
|
| `PUT` | `/api/config` | Update config (`title`, `theme`, `filenamePattern`, `extraFiles`) |
|
|
182
188
|
| `GET` | `/api/browse?path=` | List directories and `.md` files at a given filesystem path |
|
|
189
|
+
| `POST` | `/api/images/upload` | Upload a base64 image; saved to `DOCS_FOLDER/images/` |
|
|
183
190
|
|
|
184
191
|
---
|
|
185
192
|
|
|
@@ -175,16 +175,37 @@
|
|
|
175
175
|
</div>
|
|
176
176
|
<!-- Actions -->
|
|
177
177
|
<div class="flex items-center gap-2 shrink-0">
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
178
|
+
<!-- View mode actions -->
|
|
179
|
+
<div id="view-actions" class="flex items-center gap-2">
|
|
180
|
+
<button onclick="exportPDF()" title="Export as PDF"
|
|
181
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700
|
|
182
|
+
text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
183
|
+
📄 Export PDF
|
|
184
|
+
</button>
|
|
185
|
+
<button onclick="copyLink()" id="copy-link-btn" title="Copy link"
|
|
186
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700
|
|
187
|
+
text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
188
|
+
🔗 Copy link
|
|
189
|
+
</button>
|
|
190
|
+
<button onclick="enterEditMode()" title="Edit document"
|
|
191
|
+
class="no-print text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700
|
|
192
|
+
text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
193
|
+
✎ Edit
|
|
194
|
+
</button>
|
|
195
|
+
</div>
|
|
196
|
+
<!-- Edit mode actions -->
|
|
197
|
+
<div id="edit-actions" class="hidden flex items-center gap-2">
|
|
198
|
+
<span id="edit-save-msg" class="text-xs"></span>
|
|
199
|
+
<button onclick="exitEditMode()" title="Cancel editing"
|
|
200
|
+
class="text-sm px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700
|
|
201
|
+
text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
|
|
202
|
+
Cancel
|
|
203
|
+
</button>
|
|
204
|
+
<button onclick="saveDocument()" title="Save document"
|
|
205
|
+
class="text-sm px-4 py-1.5 rounded-lg bg-blue-600 hover:bg-blue-700 text-white font-semibold transition-colors">
|
|
206
|
+
Save
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
188
209
|
</div>
|
|
189
210
|
</div>
|
|
190
211
|
</header>
|
|
@@ -201,6 +222,14 @@
|
|
|
201
222
|
prose-code:before:content-none prose-code:after:content-none
|
|
202
223
|
prose-pre:bg-[#0d1117] prose-pre:border prose-pre:border-gray-700">
|
|
203
224
|
</div>
|
|
225
|
+
|
|
226
|
+
<!-- Markdown editor -->
|
|
227
|
+
<textarea id="doc-editor"
|
|
228
|
+
class="hidden w-full min-h-[70vh] px-4 py-3 text-sm font-mono leading-relaxed
|
|
229
|
+
rounded-lg border border-gray-300 dark:border-gray-600
|
|
230
|
+
bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100
|
|
231
|
+
focus:outline-none focus:ring-2 focus:ring-blue-500 resize-y"
|
|
232
|
+
spellcheck="false"></textarea>
|
|
204
233
|
</article>
|
|
205
234
|
|
|
206
235
|
</main>
|
|
@@ -211,6 +240,7 @@
|
|
|
211
240
|
// ── State ──────────────────────────────────────────────────
|
|
212
241
|
let allDocs = [];
|
|
213
242
|
let currentDocId = null;
|
|
243
|
+
let currentDocContent = '';
|
|
214
244
|
let searchQuery = '';
|
|
215
245
|
let expandedCategories = new Set();
|
|
216
246
|
|
|
@@ -384,6 +414,9 @@ async function openDocument(id, skipHistory = false) {
|
|
|
384
414
|
return r.json();
|
|
385
415
|
});
|
|
386
416
|
|
|
417
|
+
currentDocContent = doc.content;
|
|
418
|
+
exitEditMode();
|
|
419
|
+
|
|
387
420
|
document.getElementById('doc-title').textContent = doc.title;
|
|
388
421
|
document.getElementById('doc-category').textContent = doc.category;
|
|
389
422
|
document.getElementById('doc-date').textContent = doc.formattedDate || '';
|
|
@@ -465,6 +498,112 @@ async function doSearch(q) {
|
|
|
465
498
|
} catch { /* ignore */ }
|
|
466
499
|
}
|
|
467
500
|
|
|
501
|
+
// ── Edit mode ──────────────────────────────────────────────
|
|
502
|
+
function enterEditMode() {
|
|
503
|
+
const editor = document.getElementById('doc-editor');
|
|
504
|
+
editor.value = currentDocContent;
|
|
505
|
+
document.getElementById('doc-content').classList.add('hidden');
|
|
506
|
+
editor.classList.remove('hidden');
|
|
507
|
+
document.getElementById('view-actions').classList.add('hidden');
|
|
508
|
+
document.getElementById('edit-actions').classList.remove('hidden');
|
|
509
|
+
editor.focus();
|
|
510
|
+
editor.addEventListener('paste', handleEditorPaste);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function exitEditMode() {
|
|
514
|
+
const editor = document.getElementById('doc-editor');
|
|
515
|
+
editor.removeEventListener('paste', handleEditorPaste);
|
|
516
|
+
editor.classList.add('hidden');
|
|
517
|
+
document.getElementById('doc-content').classList.remove('hidden');
|
|
518
|
+
document.getElementById('edit-actions').classList.add('hidden');
|
|
519
|
+
document.getElementById('view-actions').classList.remove('hidden');
|
|
520
|
+
document.getElementById('edit-save-msg').textContent = '';
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async function handleEditorPaste(e) {
|
|
524
|
+
const items = Array.from(e.clipboardData?.items ?? []);
|
|
525
|
+
const imageItem = items.find(item => item.type.startsWith('image/'));
|
|
526
|
+
if (!imageItem) return;
|
|
527
|
+
|
|
528
|
+
e.preventDefault();
|
|
529
|
+
|
|
530
|
+
const ext = imageItem.type.split('/')[1].replace('jpeg', 'jpg') || 'png';
|
|
531
|
+
const blob = imageItem.getAsFile();
|
|
532
|
+
if (!blob) return;
|
|
533
|
+
|
|
534
|
+
const editor = document.getElementById('doc-editor');
|
|
535
|
+
const msgEl = document.getElementById('edit-save-msg');
|
|
536
|
+
|
|
537
|
+
// Insert placeholder at cursor while uploading
|
|
538
|
+
const placeholder = ``;
|
|
539
|
+
const start = editor.selectionStart;
|
|
540
|
+
const before = editor.value.slice(0, start);
|
|
541
|
+
const after = editor.value.slice(editor.selectionEnd);
|
|
542
|
+
editor.value = before + placeholder + after;
|
|
543
|
+
editor.selectionStart = editor.selectionEnd = start + placeholder.length;
|
|
544
|
+
|
|
545
|
+
msgEl.textContent = 'Uploading image…';
|
|
546
|
+
msgEl.className = 'text-xs text-gray-400';
|
|
547
|
+
|
|
548
|
+
try {
|
|
549
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
550
|
+
const reader = new FileReader();
|
|
551
|
+
reader.onload = () => resolve(reader.result);
|
|
552
|
+
reader.onerror = reject;
|
|
553
|
+
reader.readAsDataURL(blob);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const res = await fetch('/api/images/upload', {
|
|
557
|
+
method: 'POST',
|
|
558
|
+
headers: { 'Content-Type': 'application/json' },
|
|
559
|
+
body: JSON.stringify({ data: base64, ext }),
|
|
560
|
+
});
|
|
561
|
+
if (!res.ok) throw new Error(await res.text());
|
|
562
|
+
|
|
563
|
+
const { filename } = await res.json();
|
|
564
|
+
const mdImage = ``;
|
|
565
|
+
|
|
566
|
+
// Replace placeholder with final markdown
|
|
567
|
+
editor.value = editor.value.replace(placeholder, mdImage);
|
|
568
|
+
msgEl.textContent = '';
|
|
569
|
+
} catch (err) {
|
|
570
|
+
// Remove placeholder on failure
|
|
571
|
+
editor.value = editor.value.replace(placeholder, '');
|
|
572
|
+
msgEl.textContent = 'Image upload failed: ' + err.message;
|
|
573
|
+
msgEl.className = 'text-xs text-red-500 dark:text-red-400';
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
async function saveDocument() {
|
|
578
|
+
if (!currentDocId) return;
|
|
579
|
+
const content = document.getElementById('doc-editor').value;
|
|
580
|
+
const msgEl = document.getElementById('edit-save-msg');
|
|
581
|
+
msgEl.textContent = 'Saving…';
|
|
582
|
+
msgEl.className = 'text-xs text-gray-400';
|
|
583
|
+
|
|
584
|
+
try {
|
|
585
|
+
const res = await fetch('/api/documents/' + currentDocId, {
|
|
586
|
+
method: 'PUT',
|
|
587
|
+
headers: { 'Content-Type': 'application/json' },
|
|
588
|
+
body: JSON.stringify({ content }),
|
|
589
|
+
});
|
|
590
|
+
if (!res.ok) throw new Error(await res.text());
|
|
591
|
+
|
|
592
|
+
currentDocContent = content;
|
|
593
|
+
|
|
594
|
+
// Re-fetch rendered HTML and update view
|
|
595
|
+
const doc = await fetch('/api/documents/' + currentDocId).then(r => r.json());
|
|
596
|
+
const contentEl = document.getElementById('doc-content');
|
|
597
|
+
contentEl.innerHTML = doc.html;
|
|
598
|
+
contentEl.querySelectorAll('pre code').forEach(block => hljs.highlightElement(block));
|
|
599
|
+
|
|
600
|
+
exitEditMode();
|
|
601
|
+
} catch (err) {
|
|
602
|
+
msgEl.textContent = 'Save failed: ' + err.message;
|
|
603
|
+
msgEl.className = 'text-xs text-red-500 dark:text-red-400';
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
468
607
|
// ── Helpers ────────────────────────────────────────────────
|
|
469
608
|
function exportPDF() { window.print(); }
|
|
470
609
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../src/routes/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../src/routes/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAwEpD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA8IxD"}
|
|
@@ -10,6 +10,21 @@ const path_1 = __importDefault(require("path"));
|
|
|
10
10
|
const marked_1 = require("marked");
|
|
11
11
|
const parser_1 = require("../lib/parser");
|
|
12
12
|
const config_1 = require("../lib/config");
|
|
13
|
+
function collectMdFiles(dir, baseDir) {
|
|
14
|
+
const results = [];
|
|
15
|
+
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
16
|
+
if (entry.name.startsWith('.'))
|
|
17
|
+
continue;
|
|
18
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
19
|
+
if (entry.isDirectory()) {
|
|
20
|
+
results.push(...collectMdFiles(fullPath, baseDir));
|
|
21
|
+
}
|
|
22
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
|
|
23
|
+
results.push(path_1.default.relative(baseDir, fullPath));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return results;
|
|
27
|
+
}
|
|
13
28
|
function listDocs(docsPath, extraFiles = [], filenamePattern) {
|
|
14
29
|
// Extra files first, in config order, always General
|
|
15
30
|
const extraDocs = [];
|
|
@@ -24,20 +39,18 @@ function listDocs(docsPath, extraFiles = [], filenamePattern) {
|
|
|
24
39
|
category: 'General',
|
|
25
40
|
});
|
|
26
41
|
}
|
|
27
|
-
// Regular docs
|
|
28
|
-
const regularDocs =
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (b.date)
|
|
38
|
-
return 1;
|
|
39
|
-
return a.title.localeCompare(b.title);
|
|
42
|
+
// Regular docs: recursive scan, sorted by relative path
|
|
43
|
+
const regularDocs = collectMdFiles(docsPath, docsPath).map((relPath) => {
|
|
44
|
+
const filename = path_1.default.basename(relPath);
|
|
45
|
+
const subdir = path_1.default.dirname(relPath);
|
|
46
|
+
const meta = (0, parser_1.parseFilename)(filename, filenamePattern);
|
|
47
|
+
const id = encodeURIComponent(relPath.slice(0, -3));
|
|
48
|
+
const category = meta.category === 'General' && subdir !== '.'
|
|
49
|
+
? subdir.replace(/[_-]+/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
|
|
50
|
+
: meta.category;
|
|
51
|
+
return { ...meta, id, filename: relPath, category };
|
|
40
52
|
});
|
|
53
|
+
regularDocs.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
41
54
|
return [...extraDocs, ...regularDocs];
|
|
42
55
|
}
|
|
43
56
|
function safeFilePath(docsPath, filename) {
|
|
@@ -146,6 +159,42 @@ function documentsRouter(docsPath) {
|
|
|
146
159
|
res.status(500).json({ error: 'Failed to read document' });
|
|
147
160
|
}
|
|
148
161
|
});
|
|
162
|
+
// PUT /api/documents/:id — update document content
|
|
163
|
+
router.put('/:id', (req, res) => {
|
|
164
|
+
const id = decodeURIComponent(req.params.id);
|
|
165
|
+
const { content } = req.body;
|
|
166
|
+
if (typeof content !== 'string') {
|
|
167
|
+
return res.status(400).json({ error: 'content is required' });
|
|
168
|
+
}
|
|
169
|
+
const { extraFiles = [] } = (0, config_1.readConfig)(docsPath);
|
|
170
|
+
// Extra file: id is an absolute path without .md
|
|
171
|
+
if (path_1.default.isAbsolute(id)) {
|
|
172
|
+
const filePath = id + '.md';
|
|
173
|
+
if (!extraFiles.includes(filePath)) {
|
|
174
|
+
return res.status(403).json({ error: 'Access denied' });
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
fs_1.default.writeFileSync(filePath, content, 'utf-8');
|
|
178
|
+
return res.json({ ok: true });
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return res.status(500).json({ error: 'Failed to write document' });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Normal file inside docsPath
|
|
185
|
+
const filename = id + '.md';
|
|
186
|
+
const filePath = safeFilePath(docsPath, filename);
|
|
187
|
+
if (!filePath) {
|
|
188
|
+
return res.status(403).json({ error: 'Access denied' });
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
fs_1.default.writeFileSync(filePath, content, 'utf-8');
|
|
192
|
+
return res.json({ ok: true });
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return res.status(500).json({ error: 'Failed to write document' });
|
|
196
|
+
}
|
|
197
|
+
});
|
|
149
198
|
return router;
|
|
150
199
|
}
|
|
151
200
|
//# sourceMappingURL=documents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../../src/routes/documents.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../../src/routes/documents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../../src/routes/images.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAIpD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuCrD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.imagesRouter = imagesRouter;
|
|
7
|
+
const express_1 = require("express");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
function imagesRouter(docsPath) {
|
|
11
|
+
const router = (0, express_1.Router)();
|
|
12
|
+
// POST /api/images/upload — save a base64-encoded image to DOCS_FOLDER/images/
|
|
13
|
+
router.post('/upload', (req, res) => {
|
|
14
|
+
const { data, ext } = req.body;
|
|
15
|
+
if (typeof data !== 'string' || !data) {
|
|
16
|
+
return res.status(400).json({ error: 'data is required' });
|
|
17
|
+
}
|
|
18
|
+
const safeExt = (typeof ext === 'string' ? ext.replace(/[^a-z0-9]/gi, '') : 'png').toLowerCase() || 'png';
|
|
19
|
+
// Strip base64 data URL prefix if present
|
|
20
|
+
const base64 = data.replace(/^data:image\/[^;]+;base64,/, '');
|
|
21
|
+
const imagesDir = path_1.default.join(docsPath, 'images');
|
|
22
|
+
if (!fs_1.default.existsSync(imagesDir)) {
|
|
23
|
+
fs_1.default.mkdirSync(imagesDir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
const now = new Date();
|
|
26
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
27
|
+
const timestamp = `${now.getFullYear()}_${pad(now.getMonth() + 1)}_${pad(now.getDate())}` +
|
|
28
|
+
`_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
29
|
+
const random = Math.random().toString(36).slice(2, 6);
|
|
30
|
+
const filename = `image_${timestamp}_${random}.${safeExt}`;
|
|
31
|
+
const filePath = path_1.default.join(imagesDir, filename);
|
|
32
|
+
try {
|
|
33
|
+
fs_1.default.writeFileSync(filePath, Buffer.from(base64, 'base64'));
|
|
34
|
+
res.json({ filename });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
res.status(500).json({ error: 'Failed to save image' });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return router;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../../src/routes/images.ts"],"names":[],"mappings":";;;;;AAIA,oCAuCC;AA3CD,qCAAoD;AACpD,4CAAoB;AACpB,gDAAwB;AAExB,SAAgB,YAAY,CAAC,QAAgB;IAC3C,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;IAExB,+EAA+E;IAC/E,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAuC,CAAC;QAElE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YACtC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC;QAE1G,0CAA0C;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAE9D,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,YAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACtD,MAAM,SAAS,GACb,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE;YACvE,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,SAAS,SAAS,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;QAC3D,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEhD,IAAI,CAAC;YACH,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/src/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,WAAW,CAAC,EAChC,QAAQ,EACR,IAAI,EACJ,WAAmB,GACpB,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgD/B"}
|
package/dist/src/server.js
CHANGED
|
@@ -10,19 +10,23 @@ const child_process_1 = require("child_process");
|
|
|
10
10
|
const documents_1 = require("./routes/documents");
|
|
11
11
|
const config_1 = require("./routes/config");
|
|
12
12
|
const browse_1 = require("./routes/browse");
|
|
13
|
+
const images_1 = require("./routes/images");
|
|
13
14
|
const config_2 = require("./lib/config");
|
|
14
15
|
async function startServer({ docsPath, port, openBrowser = false, }) {
|
|
15
16
|
const app = (0, express_1.default)();
|
|
16
|
-
app.use(express_1.default.json());
|
|
17
|
+
app.use(express_1.default.json({ limit: '20mb' }));
|
|
17
18
|
// Persist initial state to .living-doc.json
|
|
18
19
|
(0, config_2.writeConfig)(docsPath, { docsFolder: docsPath, port });
|
|
19
20
|
// API
|
|
20
21
|
app.use('/api/documents', (0, documents_1.documentsRouter)(docsPath));
|
|
21
22
|
app.use('/api/config', (0, config_1.configRouter)(docsPath));
|
|
22
23
|
app.use('/api/browse', (0, browse_1.browseRouter)());
|
|
24
|
+
app.use('/api/images', (0, images_1.imagesRouter)(docsPath));
|
|
23
25
|
// Static frontend assets
|
|
24
26
|
const frontendPath = path_1.default.join(__dirname, 'frontend');
|
|
25
27
|
app.use(express_1.default.static(frontendPath));
|
|
28
|
+
// Static assets from docs folder (images, etc.)
|
|
29
|
+
app.use('/images', express_1.default.static(path_1.default.join(docsPath, 'images')));
|
|
26
30
|
app.get('/', (_req, res) => res.sendFile(path_1.default.join(frontendPath, 'index.html')));
|
|
27
31
|
app.get('/admin', (_req, res) => res.sendFile(path_1.default.join(frontendPath, 'admin.html')));
|
|
28
32
|
return new Promise((resolve) => {
|
package/dist/src/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "living-documentation",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A CLI tool that serves a local Markdown documentation viewer",
|
|
5
5
|
"main": "dist/src/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
],
|
|
25
25
|
"author": "Youssef MEDAGHRI-ALAOUI",
|
|
26
26
|
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/craftskillz/living-documentation.git"
|
|
30
|
+
},
|
|
27
31
|
"dependencies": {
|
|
28
32
|
"commander": "^12.1.0",
|
|
29
33
|
"express": "^4.19.2",
|