Een dating-app op basis van brieven, niet van gezichten!
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
import { Postbode } from "./plugin";
/*
* Het logboek van het toestel: wat er een native plugin in gaat en wat eruit komt. Dit zit ook in
* de release, want een fout die je niet kunt uitlezen is een fout waar je niets aan hebt — wie met
* een toestel voor je staat waarop het misgaat, is uit te lezen met
*
* adb -s <serial> logcat -s Liefdesbrieven
*
* (de eigenaar moet daarvoor ontwikkelaarsopties en usb-foutopsporing aanzetten en de computer
* eenmalig toestaan; zonder dat komt er niemand bij). De regels blijven op het toestel: ze gaan
* naar het Android-logboek en nergens anders heen — geen server, geen bestand, geen tweede partij.
* Andere apps kunnen er niet bij, dat kan sinds Android 4.1 alleen het systeem zelf.
*
* Waarom via de plugin en niet met console.log: Capacitor stuurt de console van de webview alleen
* naar logcat in een debug-build. Die brug helemaal openzetten (loggingBehavior "production") zet
* ook Capacitor's eigen regels aan, en die bevatten de ruwe invoer van élke plugin-aanroep — daar
* staat het sessietoken in. Deze weg logt alleen wat hieronder is klaargemaakt, en verder niets.
*
* Wat er met opzet niet in komt: het sessietoken, wachtwoorden, en de onafgeronde coördinaten. Een
* logregel is een kopie die blijft liggen, en van een toegangsbewijs is alleen interessant óf het
* er was en hoe lang het is. Wie een precieze locatie in een logboek zet, heeft haar alsnog
* opgeschreven.
*/
const GEHEIM = /^(token|password|wachtwoord|authorization|apikey)$/i;
/* Een geheim wordt zijn lengte: genoeg om te zien of het er was, te weinig om het te gebruiken */
const verkort = (v) => (typeof v === "string" && v !== "" ? `<${v.length} tekens>` : "<leeg>");
/* Waarden klaarmaken om te tonen; geheime velden worden vervangen, de rest gaat zoals hij is */
const schoon = (waarde) => {
if (waarde === null || typeof waarde !== "object") return waarde;
if (Array.isArray(waarde)) return waarde.map(schoon);
return Object.fromEntries(
Object.entries(waarde).map(([k, v]) => [k, GEHEIM.test(k) ? verkort(v) : schoon(v)])
);
};
/* Naar één regel, want logcat knipt op regels. Onleesbaar (cyclisch) mag nooit de app breken. */
export const toon = (waarde) => {
if (waarde === undefined) return "undefined";
try {
return JSON.stringify(schoon(waarde));
} catch {
return String(waarde);
}
};
/*
* Een regel wegschrijven mag nooit iets kapotmaken: het logboek is er om een storing te kunnen
* zien, niet om er zelf een te worden. Vandaar de vangnetten en het bewust niet afwachten van de
* plugin — logregels horen niet in de weg te lopen van waar de gebruiker op wacht.
*/
export const log = (...delen) => {
const regel = delen.map((d) => (typeof d === "string" ? d : toon(d))).join(" ");
if (Postbode) {
try {
Postbode.log({ regel }).catch(() => {});
} catch {
/* een app-versie die deze methode nog niet kent: dan geen regel, en verder niets aan de hand */
}
} else {
console.log("[liefdesbrieven]", regel); // de browser tijdens het ontwikkelen
}
};
/*
* Eén aanroep mét zijn antwoord. Beide kanten komen in het log: wat erin ging en wat eruit kwam —
* of de afwijzing, en dan vooral de `code`, want daar zet een Capacitor-plugin de eigenlijke reden
* in ("location-disabled", "location-timeout", …). De boodschap alleen is te vaag om iets aan te
* hebben.
*/
export async function gelogd(naam, invoer, fn) {
log(`→ ${naam}`, toon(invoer));
try {
const uit = await fn();
log(`← ${naam}`, toon(uit));
return uit;
} catch (e) {
log(`✗ ${naam}`, toon({ code: e?.code ?? null, message: e?.message ?? String(e) }));
throw e;
}
}