Files
Jannik 99d9fa6b7c
CI / test (push) Canceled after 0s
CI / webapp (push) Canceled after 0s
v2.0.5: Background-Sync in PWA + Sync-Queue + 8 Tests (Phase 4.3 erweitert)
Phase 4.3 (Background-Sync):
- webapp/src/sync-queue.ts: localStorage-basierte Queue
  - enqueueSync, dequeueSync, loadQueue, saveQueue, clearQueue
  - TypeScript mit korrekten Typen
- webapp/src/EditorWithLoad.tsx: erweitert
  - Auto-Sync-Toggle (localStorage-Persistenz)
  - Online-Event-Listener: processQueue bei reconnect
  - Bei Auto-Sync: direkt speichern + sync
  - Bei Offline: in Queue, wird bei 'online' verarbeitet
  - Pending-Counter im UI
- webapp/public/service-worker.js: Background-Sync
  - 'sync'-Event-Handler mit tag 'mindomat-sync'
  - Ruft POST /api/sync, postet Ergebnis an Clients
  - Browser-Support: Chrome/Edge (Background-Sync API)

Tests:
- tests/sync-queue.test.ts: 8 neue Tests
  - Startzustand, enqueue, FIFO, dequeue, clearQueue
  - Roundtrip, kaputtes JSON
  - localStorage-Mock

Verifiziert:
- 79/79 Tests gruen (10 neu seit v2.0.4)
- Webapp tsc + build OK
- EditorWithLoad funktional mit Auto-Sync-Option

Pfad-Korrekturen:
- vite.config.ts: ../../src/ -> ../src/ (war falsch, webapp ist nur 1 Ebene tiefer)
2026-09-05 12:38:34 +02:00

83 lines
2.6 KiB
TypeScript

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'node:path';
import { NotesApi } from '../src/notes-api-server.js';
const VAULT_PATH = process.env.MINDOMAT_VAULT_PATH ?? 'C:/GitHub/Mind-o-Mat-Vault';
// Vite-Plugin: API-Endpoints fuer Notes
function notesApiPlugin() {
return {
name: 'mindomat-notes-api',
configureServer(server: any) {
const api = new NotesApi(VAULT_PATH);
// GET /api/notes -> Liste aller Notiz-IDs
server.middlewares.use('/api/notes', (req: any, res: any, next: any) => {
if (req.method !== 'GET') return next();
try {
const notes = api.listNotes();
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ notes }));
} catch (err) {
res.statusCode = 500;
res.end(JSON.stringify({ error: (err as Error).message }));
}
});
// GET/PUT /api/notes/<id>
server.middlewares.use('/api/notes/', (req: any, res: any, next: any) => {
const idParam = decodeURIComponent(req.url.slice(1));
if (req.method === 'GET') {
const note = api.getNote(idParam);
if (!note) {
res.statusCode = 404;
res.end('Not found');
return;
}
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(note));
return;
}
if (req.method === 'PUT') {
let body = '';
req.on('data', (chunk: Buffer) => { body += chunk.toString(); });
req.on('end', () => {
try {
const data = JSON.parse(body);
const result = api.saveNote(idParam, data.content ?? '');
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(result));
} catch (err) {
res.statusCode = 500;
res.end(JSON.stringify({ error: (err as Error).message }));
}
});
return;
}
next();
});
// POST /api/sync -> ruft mindomat sync auf
server.middlewares.use('/api/sync', (req: any, res: any, next: any) => {
if (req.method !== 'POST') return next();
api.syncVault(resolve(__dirname, '..', 'bin', 'mindomat.mjs')).then((result: { ok: boolean; message: string }) => {
res.setHeader('Content-Type', 'application/json');
if (!result.ok) res.statusCode = 500;
res.end(JSON.stringify(result));
});
});
},
};
}
export default defineConfig({
plugins: [react(), notesApiPlugin()],
server: {
port: 5173,
open: true,
},
});