fix(teilen): Basis-Adresse per Lebendprobe prüfen, sonst fragen (D81-Nachtrag)
Auf einer Instanz ohne eigenes Backend (GitHub Pages) endete Teilen mit HTTP 405: Die Vorgabe "eigene Herkunft" (D76-Nachtrag 8) stimmt nur auf der produktiven Installation. serverBaseOrAsk() prüft die Vorgabe jetzt mit GET /api/v1/info (D77), bevor gePOSTet wird, und fragt sonst nach der Server-Adresse; gemerkt wird nur eine Adresse, die die Probe besteht. Von Pages aus trägt man werkbaum.javagil.de ein — CORS erlaubt es. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4be6ecb984
commit
67d0ef421b
@@ -17,6 +17,10 @@ the git history of `docs/examples/werkbaum.werkbaum`. A day can therefore carry
|
|||||||
a link without having a note (someone forgot to write one) — but never the
|
a link without having a note (someone forgot to write one) — but never the
|
||||||
reverse.
|
reverse.
|
||||||
|
|
||||||
|
## 2026-08-27
|
||||||
|
|
||||||
|
- Fix: sharing from an instance without its own backend (GitHub Pages) failed with HTTP 405 — the share button now probes the default address and asks for the server instead
|
||||||
|
|
||||||
## 2026-08-26
|
## 2026-08-26
|
||||||
|
|
||||||
- The document picker moved into the app header: `Werkbaum › name` opens the menu — on the phone it is reachable from both panes, and the name takes over the subtitle line
|
- The document picker moved into the app header: `Werkbaum › name` opens the menu — on the phone it is reachable from both panes, and the name takes over the subtitle line
|
||||||
|
|||||||
@@ -7006,3 +7006,38 @@ stellt Text und Knopfzustände zurück, ohne das Menü zu schließen; Löschen
|
|||||||
eines nicht-aktiven Dokuments lässt den Editor unangetastet; auf dem Telefon
|
eines nicht-aktiven Dokuments lässt den Editor unangetastet; auf dem Telefon
|
||||||
ist der Wähler aus dem Diagramm-Bereich erreichbar und der Wechsel rendert
|
ist der Wähler aus dem Diagramm-Bereich erreichbar und der Wechsel rendert
|
||||||
183 Knoten, langer Name füllt die 335-px-Chipzeile mit Ellipse.
|
183 Knoten, langer Name füllt die 335-px-Chipzeile mit Ellipse.
|
||||||
|
|
||||||
|
**Nachtrag — vor dem Teilen wird die Basis-Adresse per Lebendprobe geprüft.**
|
||||||
|
Gemeldet vom ersten echten Druck auf den neuen Teilen-Knopf: „Server-Dokument
|
||||||
|
nicht geladen: https://mhoennig.github.io/api/v1/documents (HTTP 405)." Die
|
||||||
|
Ursache liegt nicht im Knopf, sondern in der Vorgabe aus D76-Nachtrag 8: Die
|
||||||
|
Basis-Adresse ist die **eigene Herkunft** — richtig auf der produktiven
|
||||||
|
Installation (dort liegt `/api/` per Proxy dahinter, D77), falsch auf jeder
|
||||||
|
statischen Instanz. GitHub Pages beantwortet den POST mit 405, und die
|
||||||
|
Meldung führte auf die falsche Fährte („ist die Adresse eine
|
||||||
|
Dokument-Adresse?"). Der Fehler war schon vor D81 da; der Knopf in der
|
||||||
|
Titelzeile hat ihn nur sichtbar gemacht — im Menü hat ihn dort schlicht
|
||||||
|
niemand gedrückt.
|
||||||
|
|
||||||
|
**Gefixt mit der Lebendprobe, die es schon gibt:** `GET /api/v1/info` (D77,
|
||||||
|
gebaut genau als „antwortet hier die Anwendung?"). `serverBaseOrAsk()` prüft
|
||||||
|
die Vorgabe damit, **bevor** gePOSTet wird; besteht sie nicht, wird
|
||||||
|
**gefragt** — der vorhandene Dialog samt gemerkter Antwort. Gemerkt wird nur
|
||||||
|
eine Adresse, die die Probe besteht: Ein Tippfehler klemmt sich nicht fest
|
||||||
|
(und eine gemerkte Adresse, deren Backend verschwindet, heilt sich beim
|
||||||
|
nächsten Teilen von selbst — Probe scheitert, es wird neu gefragt). Eine
|
||||||
|
eingegebene Adresse, die nicht antwortet, wird trotzdem versucht — der
|
||||||
|
POST-Fehlerpfad nennt dann ehrlich, was nicht erreichbar war, statt dass der
|
||||||
|
Dialog stumm wieder aufgeht.
|
||||||
|
|
||||||
|
**Von Pages aus funktioniert das Teilen damit wirklich:** Das Backend erlaubt
|
||||||
|
CORS `*` (D76-Nachtrag 7) — wer auf `mhoennig.github.io` arbeitet und im
|
||||||
|
Dialog `https://werkbaum.javagil.de` einträgt, legt sein Dokument dort ab.
|
||||||
|
Gemessen aus dem Browser: Die Probe gegen die stabile Instanz besteht
|
||||||
|
cross-origin.
|
||||||
|
|
||||||
|
**Nachgemessen** am Dev-Server (dieselbe Lage wie Pages: keine eigene
|
||||||
|
`/api/`): Teilen öffnet jetzt den Adress-Dialog statt der 405-Warnung,
|
||||||
|
Abbruch tut nichts; die Probe gegen das echte Backend liefert
|
||||||
|
`{name:"editor-backend"}`. `infoUrl()` liegt headless in live.js (39
|
||||||
|
Live-Tests, +1).
|
||||||
|
|||||||
+25
-5
@@ -4866,27 +4866,47 @@ function displayName(){
|
|||||||
const SERVER_PARAM = 'server';
|
const SERVER_PARAM = 'server';
|
||||||
const LS_SERVER = 'werkbaum-server';
|
const LS_SERVER = 'werkbaum-server';
|
||||||
|
|
||||||
|
/* Antwortet unter dieser Basis wirklich ein Werkbaum-Backend? Die Lebendprobe
|
||||||
|
`/api/v1/info` (D77), bevor blind gePOSTet wird. */
|
||||||
|
async function probeServer(basis){
|
||||||
|
try{
|
||||||
|
const info = await fetchJson(live.infoUrl(basis));
|
||||||
|
return !!(info && info.name);
|
||||||
|
}catch(_){ return false; }
|
||||||
|
}
|
||||||
|
|
||||||
/* Wohin? Reihenfolge und Begründung stehen in live.js. Was dort nicht
|
/* Wohin? Reihenfolge und Begründung stehen in live.js. Was dort nicht
|
||||||
hingehört, ist der letzte Ausweg: fragen und die Antwort merken — ein
|
hingehört, ist der letzte Ausweg: fragen und die Antwort merken — ein
|
||||||
Dialog ist keine entscheidbare Regel. */
|
Dialog ist keine entscheidbare Regel.
|
||||||
function serverBaseOrAsk(){
|
|
||||||
|
Die Vorgabe „eigene Herkunft" stimmt nur, wo das Backend wirklich dahinter
|
||||||
|
liegt (produktive Installation, D77) — auf GitHub Pages oder einer anderen
|
||||||
|
statischen Instanz gibt es keins, und der POST endete dort mit einem
|
||||||
|
kryptischen 405 (D81-Nachtrag). Deshalb wird die Vorgabe erst per
|
||||||
|
Lebendprobe geprüft und sonst GEFRAGT; gemerkt wird nur eine Adresse, die
|
||||||
|
die Probe besteht — ein Tippfehler klemmt sich so nicht fest. Eine
|
||||||
|
eingegebene Adresse, die nicht antwortet, wird trotzdem versucht: Der
|
||||||
|
POST-Fehlerpfad nennt dann ehrlich, was nicht erreichbar war. */
|
||||||
|
async function serverBaseOrAsk(){
|
||||||
const offen = liveState ? liveState.urls.doc : null;
|
const offen = liveState ? liveState.urls.doc : null;
|
||||||
let gemerkt = null;
|
let gemerkt = null;
|
||||||
try{ gemerkt = localStorage.getItem(LS_SERVER); }catch(_){}
|
try{ gemerkt = localStorage.getItem(LS_SERVER); }catch(_){}
|
||||||
const basis = live.serverBase(urlParam(SERVER_PARAM) || gemerkt, offen, location.href);
|
const basis = live.serverBase(urlParam(SERVER_PARAM) || gemerkt, offen, location.href);
|
||||||
if(basis) return basis;
|
if(basis && await probeServer(basis)) return basis;
|
||||||
|
|
||||||
const eingabe = window.prompt(t('docToServerAsk'), 'https://');
|
const eingabe = window.prompt(t('docToServerAsk'), 'https://');
|
||||||
if(!eingabe) return null;
|
if(!eingabe) return null;
|
||||||
const geprueft = live.serverBase(eingabe, null, location.href);
|
const geprueft = live.serverBase(eingabe, null, location.href);
|
||||||
if(geprueft){ try{ localStorage.setItem(LS_SERVER, geprueft); }catch(_){} }
|
if(geprueft && await probeServer(geprueft)){
|
||||||
|
try{ localStorage.setItem(LS_SERVER, geprueft); }catch(_){}
|
||||||
|
}
|
||||||
return geprueft;
|
return geprueft;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function putOnServer(){
|
async function putOnServer(){
|
||||||
const d = activeDoc();
|
const d = activeDoc();
|
||||||
if(!d) return;
|
if(!d) return;
|
||||||
const basis = serverBaseOrAsk();
|
const basis = await serverBaseOrAsk();
|
||||||
if(!basis) return;
|
if(!basis) return;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|||||||
@@ -77,6 +77,14 @@ export function documentsUrl(base){
|
|||||||
return String(base).replace(/\/+$/, '') + '/api/v1/documents';
|
return String(base).replace(/\/+$/, '') + '/api/v1/documents';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lebendprobe (D77): antwortet hier wirklich ein Werkbaum-Backend? Vor dem
|
||||||
|
Teilen gefragt, denn die Vorgabe „eigene Herkunft" stimmt nur auf der
|
||||||
|
produktiven Installation — auf einer statischen Instanz (GitHub Pages)
|
||||||
|
bekäme der POST sonst ein kryptisches 405 (D81-Nachtrag). */
|
||||||
|
export function infoUrl(base){
|
||||||
|
return String(base).replace(/\/+$/, '') + '/api/v1/info';
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ Zeilen */
|
/* ------------------------------------------------------------------ Zeilen */
|
||||||
|
|
||||||
/* Zeilenenden auf LF (SPEC §12). Der Server normalisiert beim Speichern
|
/* Zeilenenden auf LF (SPEC §12). Der Server normalisiert beim Speichern
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {describe, it, expect} from 'vitest';
|
import {describe, it, expect} from 'vitest';
|
||||||
import {
|
import {
|
||||||
liveUrls, normalize, lines, text, computeOps, applyOps,
|
liveUrls, normalize, lines, text, computeOps, applyOps,
|
||||||
mapLine, caretToLineCol, lineColToCaret, feedAction, serverBase, documentsUrl,
|
mapLine, caretToLineCol, lineColToCaret, feedAction, serverBase, documentsUrl, infoUrl,
|
||||||
} from '../src/live.js';
|
} from '../src/live.js';
|
||||||
|
|
||||||
describe('Adressen', () => {
|
describe('Adressen', () => {
|
||||||
@@ -195,6 +195,12 @@ describe('Basis-Adresse des Backends', () => {
|
|||||||
.toBe('https://werkbaum.example/api/v1/documents');
|
.toBe('https://werkbaum.example/api/v1/documents');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('die Lebendprobe fragt /api/v1/info an der Basis (D81-Nachtrag)', () => {
|
||||||
|
expect(infoUrl('https://werkbaum.example')).toBe('https://werkbaum.example/api/v1/info');
|
||||||
|
expect(infoUrl('https://werkbaum.example/unterverzeichnis/'))
|
||||||
|
.toBe('https://werkbaum.example/unterverzeichnis/api/v1/info');
|
||||||
|
});
|
||||||
|
|
||||||
it('der ?server=-Parameter hat Vorrang', () => {
|
it('der ?server=-Parameter hat Vorrang', () => {
|
||||||
expect(serverBase('http://localhost:8080', 'https://fremd.example/api/v1/documents/x', seite))
|
expect(serverBase('http://localhost:8080', 'https://fremd.example/api/v1/documents/x', seite))
|
||||||
.toBe('http://localhost:8080');
|
.toBe('http://localhost:8080');
|
||||||
|
|||||||
Reference in New Issue
Block a user