pageta/apps/extension/README.md
Till JS db005b6307 docs(extension): Prüf-Anleitung und ehrlicher Teststand
Was maschinell geprüft ist, steht jetzt namentlich da — Manifest,
Berechtigungs-Rahmen, Syntax, Sammel-Logik (12 Tests) und der Transport
End-to-End gegen die Live-Instanz (POST → 303 → Einweg-Token → Abholung →
zweite Abholung 404).

Ungetestet bleibt genau die MV3-Verdrahtung dazwischen: action.onClicked →
scripting.executeScript → fetch mit credentials. Die braucht einen echten
Browser-Load; eine Automatisierung darf chrome://extensions nicht bedienen.
Dafür jetzt eine Anleitung mit erwartetem Verhalten (Golem-Artikel,
Cookie-Abfrage wegklicken, Symbol zeigt … dann ✓) und wo im Fehlerfall der
Grund steht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:48:54 +02:00

126 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pageta — Browser-Erweiterung
Ein Klick speichert die geöffnete Seite in die Lese-Liste — **mit dem Text,
den du siehst**.
## Wozu, wenn es das Bookmarklet schon gibt
Das Bookmarklet kann dasselbe, aber es muss erst in die Lesezeichenleiste
gezogen werden — für die meisten Menschen ist das die Stelle, an der sie
aufhören. Die Erweiterung ist ein Symbol in der Leiste.
Beide lösen dasselbe Problem: Quellen wie golem.de antworten auf **jede**
Anfrage ohne Cookies mit ihrer Zustimmungs-Abfrage statt mit dem Artikel —
auch dann, wenn der Abrufer sich als normaler Browser ausgibt (gemessen
2026-07-27 aus dem Produktions-Container, siehe
[`docs/EXTRAKTION.md`](../../docs/EXTRAKTION.md)). Serverseitig kommt da
nichts vorbei. Der Artikel existiert nur in deinem Tab.
## Wie sie arbeitet
```
Klick aufs Symbol
→ activeTab erlaubt EINMALIG, diesen einen Tab zu lesen
→ collectPageta() im Tab: Seite 1 + erkannte Folgeseiten, je geleichtert
→ { url, title, pages, missing }
→ POST <instanz>/lese-liste/add/receive (dieselbe Route wie das Bookmarklet)
→ 303 auf /lese-liste/add?pickup=<einweg-token> (2 Minuten gültig)
→ neuer Tab holt das Payload ab und speichert lokal-first über event-sync
```
Es gibt bewusst **einen** Eingang für Bookmarklet und Erweiterung. Zwei
Transportwege für dieselbe Sache wären zwei Wege, die auseinanderdriften.
## Mehrseitige Artikel
Ein Artikel auf drei Seiten liegt komplett hinter derselben Wand — Seite 2
holt der Server genauso wenig wie Seite 1. Also holt sie der Tab: ein
`fetch` aus der Seite heraus trägt die Sitzung mit.
Folgeseiten findet [`page-collector.js`](page-collector.js) ohne
quellenspezifische Selektoren — ein Link zählt, wenn seine Adresse sich von
der aktuellen **nur in einem Seitenzähler** unterscheidet (`-2.html`,
`?page=2`, `/seite/2/`); findet sich keine Seitenliste, folgt es der
`rel="next"`-Kette. Gedeckelt bei 20 Seiten und 6 MB, mit kurzer Pause
zwischen den Abrufen.
Diese Datei ist eine **zeichengleiche Kopie** von
`apps/web/src/lib/page-collector.js` — dieselbe Logik treibt das Bookmarklet
(dort als Quelltext in der `javascript:`-Adresse). Einen Bundler, der beide
bedient, gibt es nicht; die Erweiterung soll bewusst ohne Build auskommen.
`scripts/check.mjs` bricht ab, sobald die Kopien auseinanderlaufen.
## Was sie nicht tut
- **Keine dauerhafte Leseerlaubnis.** `activeTab` gilt für den Klick, nicht
für den Verlauf. Ohne Klick sieht die Erweiterung keine Seite.
- **Kein API-Schlüssel.** Es zählt die Anmeldung, die dein Browser ohnehin
hat. Nichts Geheimes liegt in der Erweiterung.
- **Keine Telemetrie, keine Fremd-Server, kein Hintergrund-Verkehr.**
Sie spricht ausschließlich mit deiner Pageta-Instanz, und nur wenn du
klickst.
## Lokal ausprobieren
**Chrome / Edge / Brave**
1. `chrome://extensions` → Entwicklermodus an
2. „Entpackte Erweiterung laden" → diesen Ordner wählen
3. Symbol anheften, Artikel öffnen, klicken
**Firefox** (ab 121)
1. `about:debugging#/runtime/this-firefox`
2. „Temporäres Add-on laden…" → `manifest.json` wählen
Eine andere Instanz (Selbst-Hosting) stellst du in den Erweiterungs-
Einstellungen ein; die Erlaubnis für diese Adresse wird dort abgefragt.
### Der erste Klick — was passieren soll
Nimm eine Seite mit Zustimmungs-Abfrage, an der der Server scheitert; ein
Golem-Artikel ist der verlässlichste Fall.
1. Artikel in einem Tab öffnen, Cookie-Abfrage **wegklicken** (das ist der
Punkt — die Erweiterung nutzt genau diese Zustimmung).
2. Auf das Pageta-Symbol klicken.
3. Erwartung: Symbol zeigt kurz `…`, dann `✓`; ein neuer Tab öffnet
`/lese-liste/add?pickup=…` und speichert.
4. In der Lese-Liste steht der Artikel mit **echtem Titel und Volltext** —
nicht mit „Quelle blockiert".
Wenn das Symbol `!` zeigt: Rechtsklick → „Verwaltung" → „Service Worker"
öffnet die Konsole der Erweiterung; dort steht der Grund.
Läuft der Klick auf einer internen Seite (`chrome://`, Store-Seiten) oder
auf Pageta selbst, zeigt das Symbol `–` und tut bewusst nichts.
## Paketieren
```bash
pnpm --filter @pageta/extension package # → dist/pageta-extension-<version>.zip
```
Das Zip ist das, was in den Chrome Web Store bzw. bei addons.mozilla.org
hochgeladen wird.
## Offene Punkte
- **Store-Einreichung ist nicht angestoßen.** Chrome Web Store verlangt ein
Entwicklerkonto (einmalig 5 USD) und eine Datenschutz-Begründung je
Berechtigung; Firefox verlangt Signierung. Beides ist Vereinsarbeit, keine
Programmierarbeit — bis dahin ist die Erweiterung über „entpackt laden"
nutzbar.
- **Kein Kontextmenü-Eintrag** („Link in Pageta speichern"). Braucht die
`contextMenus`-Berechtigung; erst einbauen, wenn jemand danach fragt.
- **Der Klick-Weg im Browser ist ungetestet.** Maschinell geprüft sind:
Manifest, referenzierte Dateien, Berechtigungs-Rahmen, Syntax aller
Skripte (`scripts/check.mjs`), die Sammel-Logik (12 Tests in
`apps/web/src/lib/page-collector.test.ts`) und der **Transport
End-to-End** gegen die Live-Instanz: POST → 303 → Einweg-Token →
Abholung liefert das Payload → zweite Abholung 404.
Was fehlt, ist genau die MV3-Verdrahtung dazwischen —
`action.onClicked` → `scripting.executeScript` → `fetch` mit
`credentials` cross-origin. Die braucht einen echten Browser-Load; eine
Automatisierung darf `chrome://extensions` nicht bedienen. Anleitung
oben, dauert eine Minute.