Includes ESP-IDF NFC stack (deep capture, 4K Classic geometry, UL write API, open SoftAP), React dashboard with live tag diagnostics, and docs. README updated for APIs and lab Wi-Fi defaults. Made-with: Cursor
63 lines
1.5 KiB
TypeScript
63 lines
1.5 KiB
TypeScript
/** Stored API origin; trailing slashes stripped so paths join cleanly. */
|
|
export function apiBaseUrl(): string {
|
|
return (localStorage.getItem("apiBase") || "").replace(/\/+$/, "");
|
|
}
|
|
|
|
export function apiUrl(path: string): string {
|
|
const b = apiBaseUrl();
|
|
const p = path.startsWith("/") ? path : `/${path}`;
|
|
return b ? `${b}${p}` : p;
|
|
}
|
|
|
|
export async function apiGet<T>(path: string): Promise<T> {
|
|
const r = await fetch(apiUrl(path));
|
|
if (!r.ok) {
|
|
throw new Error(await r.text());
|
|
}
|
|
return r.json() as Promise<T>;
|
|
}
|
|
|
|
export async function apiPost<T>(path: string, body: unknown): Promise<T> {
|
|
const r = await fetch(apiUrl(path), {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
});
|
|
if (!r.ok) {
|
|
throw new Error(await r.text());
|
|
}
|
|
return r.json() as Promise<T>;
|
|
}
|
|
|
|
export type SessionInfo = {
|
|
usedBytes: number;
|
|
maxBytes: number;
|
|
lines: number;
|
|
full: boolean;
|
|
deepCapture: boolean;
|
|
};
|
|
|
|
export type Status = {
|
|
app: string;
|
|
uptimeMs: number;
|
|
freeHeap: number;
|
|
wifiMode: number;
|
|
pn532?: { ic: number; fwHi: number; fwLo: number };
|
|
scanning: boolean;
|
|
session?: SessionInfo;
|
|
};
|
|
|
|
export type Tag = {
|
|
uid: string;
|
|
uidLen: number;
|
|
atqa: number;
|
|
sak: number;
|
|
typeHint: number;
|
|
/** ATQA as 4 hex digits (MSB first, same as firmware). */
|
|
atqaHex?: string;
|
|
sakHex?: string;
|
|
typeGuess?: string;
|
|
/** PN532 `GetGeneralStatus` payload bytes (chip-dependent length). */
|
|
pn532GeneralStatus?: number[];
|
|
};
|