const _BODY_PREVIEW_MAX = 280; function _looksLikeHtmlDocument(body) { const s = String(body || "").trimStart(); if (!s) return false; if (s.startsWith("= 5 && /^<\s*html[\s>]/i.test(s.slice(0, 32))) return true; return s.startsWith(" _BODY_PREVIEW_MAX ? `${t.slice(0, _BODY_PREVIEW_MAX)}…` : t; } function _messageForFailedRequest(status, rawText, parsedPayload) { const raw = String(rawText || "").trim(); if (_looksLikeHtmlDocument(raw)) { return `Server error (${status}) — the response was a web page, not JSON. Try again in a moment.`; } if (parsedPayload && typeof parsedPayload.detail === "string" && parsedPayload.detail.trim()) { return _clipMessage(parsedPayload.detail); } if (parsedPayload && parsedPayload.detail != null) { try { return _clipMessage(JSON.stringify(parsedPayload.detail)); } catch { return `Request failed (${status})`; } } return _clipMessage(raw) || `Request failed (${status})`; } export async function api(path, options = {}) { const response = await fetch(path, options); const text = await response.text(); let payload; try { payload = text ? JSON.parse(text) : {}; } catch { if (!response.ok) { const message = _messageForFailedRequest(response.status, text, null); const error = new Error(message); error.status = response.status; error.payload = null; throw error; } return {}; } if (!response.ok) { const message = _messageForFailedRequest(response.status, text, payload); const error = new Error(message); error.status = response.status; error.payload = payload; throw error; } return payload; } export function authHeaders(token) { return token ? { "x-private-token": token } : {}; } export function uiReactionFor(rating) { if (rating === "love") return "love"; if (rating === "like") return "like"; if (rating === "curious") return "maybe"; if (rating === "not_interested") return "not_interested"; if (rating === "hard_no" || rating === "no") return "no_go"; return ""; } export function currentDirectionsFor(plays, kinkId) { return plays?.[kinkId]?.directions || []; } export { directionColumnsForPlay, directionsAfterColumnDrop } from "./direction-logic.js";