Files
tickte-system/scripts/workers-harness/scripted-fetch.js
T
ClaudeandClaude Sonnet 5.5 78c8e3fbc2 Workers P6: Prüfstand für den Reiter Bot-Leads (Desktop und Handy)
Skript-API: botleads({ room, q, page, id }) antwortet wie GET /botleads des Dienstes
(items, total, pageSize 50; Telefon nie bei Heilberufen, gekürzte Stubs nur mit id).
60 sichtbare Einträge in vier Räumen (zwei Seiten), 3 gekürzte Stubs, Heilberufe mit
Altbestand-Telefon, eine http-Quelle, zwei feindliche Quellen, lange Namen und Gründe.
Schalter: faults.botleads, botleadsDelayMs, botleadsEmpty (?botleads=leer), botleadCalls.
Fetch-Weiche und entry.jsx (?bot=<Id>) um die Route und den Deep-Link ergänzt.

Szenarien: botleads (Reiter, Liste, Raumfilter, Blättern mit Fokus, Suche, Leerzustände,
Fehlertexte, Deep-Link, Quellen-Links, Telefon) und handy-botleads (390 x 844: kein
seitliches Scrollen, Knopfhöhe, Kontrast der gekürzten Zeile, Wortumbruch).
Der Pin in workersHarness.test.mjs prüft nun die neue Antwortform statt der leeren Liste.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 14:43:33 +00:00

60 lines
4.1 KiB
JavaScript
Raw 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.
// Fetch-Weiche des Prüfstands: nimmt die Anfragen des echten API-Clients (createWorkersApi, URLs unter /api/workers) entgegen und
// beantwortet sie mit der Skript-API. Damit läuft im Prüfstand dieselbe Kette wie im Betrieb (API-Client, Feed, Board), und die
// Ausfälle lassen sich schalten: control.fault = null (gesund) | 'down' (503 ohne JSON wie eine Fehlerseite des Proxys) |
// 'session' (401) | 'hang' (die Antwort kommt nie, wie auf einer toten Verbindung). Kein Netz, kein Appwrite.
// Seit P3 auch Pult (GET /pult, POST /pult/:id/<Aktion>) und Interessent (GET /prospect/:id): Fehler der Skript-API (status + deutscher
// Satz) kommen als { error } mit diesem Status an, wie vom Dienst (auch 413 „Anfrage zu groß.“). Seit P4 laufen reply, approve-preview,
// start-build und paste über dieselbe Route POST /pult/:id/<Aktion>. Ein Fehler mit status 0 aus der Skript-API bricht die Verbindung ab
// (fetch wirft), damit die Meldung „Kann gesendet sein – Pult neu laden.“ (Zeitüberschreitung, D14) sichtbar wird.
// Seit P6 auch Bot-Leads (GET /botleads?room=&q=&page=&id=): die Route liest die Angaben wie der Dienst (fehlend = leer, page als Zahl, unlesbar = NaN).
// control.calls sammelt jede Anfrage ({ method, path, jwt }), damit der Prüfstand zählen kann.
const reply = (status, body) => ({
ok: status >= 200 && status < 300,
status,
json: async () => {
if (body === undefined) throw new SyntaxError('kein JSON')
return body
},
})
export function createScriptedFetch(api, control) {
return async function scriptedFetch(url, init = {}) {
const method = init.method || 'GET'
const parsed = new URL(url, 'http://harness.invalid')
const path = parsed.pathname.replace(/^\/api\/workers/, '')
control.calls.push({ method, path, jwt: init.headers ? init.headers['X-Appwrite-JWT'] : undefined })
if (control.fault === 'hang') return new Promise(() => {})
if (control.fault === 'down') return reply(503, undefined)
if (control.fault === 'session') return reply(401, {})
try {
const body = init.body === undefined ? undefined : JSON.parse(init.body)
if (method === 'GET' && path === '/state') return reply(200, await api.state())
if (method === 'GET' && path === '/events') {
const limit = parsed.searchParams.get('limit')
return reply(200, await api.events(parsed.searchParams.get('after'), limit === null ? undefined : Number(limit)))
}
const trace = /^\/worker\/([^/]+)\/trace$/.exec(path)
if (method === 'GET' && trace) return reply(200, await api.trace(decodeURIComponent(trace[1])))
if (method === 'POST' && path === '/pause') return reply(200, await api.pause(body.paused))
if (method === 'GET' && path === '/settings') return reply(200, await api.settings())
if (method === 'PUT' && path === '/settings') return reply(200, await api.saveSettings(body))
// Freigabe-Pult und Interessent (P3); ohne ?status= gilt wie im Dienst offen,in_arbeit
if (method === 'GET' && path === '/pult') return reply(200, await api.pult(parsed.searchParams.get('status') ?? undefined))
const action = /^\/pult\/([^/]+)\/([^/]+)$/.exec(path)
if (method === 'POST' && action) return reply(200, await api.pultAction(decodeURIComponent(action[1]), action[2], body))
if (method === 'GET' && path === '/botleads') {
const query = parsed.searchParams
return reply(200, await api.botleads({ room: query.get('room') ?? '', q: query.get('q') ?? '', page: Number(query.get('page') ?? ''), id: query.get('id') ?? '' }))
}
const prospect = /^\/prospect\/([^/]+)$/.exec(path)
if (method === 'GET' && prospect) return reply(200, await api.prospect(decodeURIComponent(prospect[1])))
return reply(404, { error: 'Unbekannter Pfad im Prüfstand.' })
} catch (err) {
// Status 0 aus der Skript-API = die Verbindung bricht ab, bevor eine Antwort da ist (fetch wirft wie bei einem Netzfehler)
if (err && err.status === 0) throw new TypeError('Failed to fetch')
return reply(err && err.status ? err.status : 500, { error: err && err.message ? err.message : 'Fehler im Prüfstand.' })
}
}
}