From 98bce1b0da675715b2e5482c0ad61ba21135f62f Mon Sep 17 00:00:00 2001
From: Server-Bibliothek <server-bibliothek@lokal>
Date: Di, 04 Aug 2026 07:00:04 +0200
Subject: [PATCH] Add a desktop client that knows what is installed locally

---
 packages/bibliothek-server/src/bezugsquellen/direkt-link.ts |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/packages/bibliothek-server/src/bezugsquellen/direkt-link.ts b/packages/bibliothek-server/src/bezugsquellen/direkt-link.ts
new file mode 100644
index 0000000..e5d35b2
--- /dev/null
+++ b/packages/bibliothek-server/src/bezugsquellen/direkt-link.ts
@@ -0,0 +1,40 @@
+import {
+  abgleichMisserfolg,
+  alsIsoDatum,
+  dateinameAusUrl,
+  dateiVorhanden,
+  ersetzeDateiSicher,
+  inhaltBeanstanden,
+  type Abgleichauftrag,
+  type Bezugsquelle,
+  type QuellenAbgleich,
+} from './basis';
+
+/** Direkter Download-Link: lädt die Datei, erkennt Änderungen über ETag/Last-Modified. */
+export class DirektLinkQuelle implements Bezugsquelle {
+  async gleicheAb(auftrag: Abgleichauftrag): Promise<QuellenAbgleich> {
+    try {
+      const antwort = await fetch(auftrag.wert, { redirect: 'follow' });
+      if (!antwort.ok) {
+        return abgleichMisserfolg(auftrag.aktuelleVersion, `Server nicht erreichbar (HTTP ${antwort.status}).`);
+      }
+      const kennung = antwort.headers.get('etag') ?? antwort.headers.get('last-modified') ?? '';
+      const veroeffentlichtAm = alsIsoDatum(antwort.headers.get('last-modified'));
+      const dateiname = dateinameAusUrl(auftrag.wert);
+      if (kennung && kennung === auftrag.aktuelleVersion && dateiVorhanden(auftrag.zielordner, dateiname)) {
+        return { erfolg: true, geaendert: false, version: kennung, dateiname, meldung: 'Bereits aktuell.', veroeffentlichtAm };
+      }
+
+      const inhalt = Buffer.from(await antwort.arrayBuffer());
+      const beanstandung = inhaltBeanstanden(inhalt, dateiname, antwort.headers.get('content-type'), auftrag.vorherigeGroesse);
+      if (beanstandung) {
+        return abgleichMisserfolg(auftrag.aktuelleVersion, beanstandung);
+      }
+
+      ersetzeDateiSicher(auftrag.zielordner, dateiname, inhalt);
+      return { erfolg: true, geaendert: true, version: kennung || new Date().toISOString(), dateiname, meldung: 'Aktualisiert.', veroeffentlichtAm };
+    } catch (fehler) {
+      return abgleichMisserfolg(auftrag.aktuelleVersion, `Download fehlgeschlagen: ${fehler instanceof Error ? fehler.message : String(fehler)}`);
+    }
+  }
+}

--
Gitblit v1.9.3