// lib/api.ts - API helpers with Zod validation for your Laravel endpoints import { z } from "zod"; export type DeviceCommandType = | "wifi" | "sleep" | "telemetry_sec" | "poll_sec" | "ota" | "ring_fence" | "lights" | "camera"; export interface DeviceCommand { id: number; type: DeviceCommandType; payload: Record; } export interface TelemetryPost { recorded_at?: string; lat: number; lng: number; altitude_m?: number; speed_kmh?: number; heading_deg?: number; accuracy_m?: number; battery_percent?: number; is_car_on?: boolean; raw?: Record; } export interface CommandReceiptPost { command_id: number; acked_at?: string; executed_at?: string; result?: "ok" | "error"; result_detail?: string; } // Zod schemas for validation const telemetrySchema = z.object({ recorded_at: z.string().optional(), lat: z.number(), lng: z.number(), altitude_m: z.number().optional(), speed_kmh: z.number().optional(), heading_deg: z.number().optional(), accuracy_m: z.number().optional(), battery_percent: z.number().optional(), is_car_on: z.boolean().optional(), raw: z.record(z.unknown()).optional(), }); const receiptSchema = z.object({ command_id: z.number(), acked_at: z.string().optional(), executed_at: z.string().optional(), result: z.enum(["ok", "error"]).optional(), result_detail: z.string().optional(), }); // API base from हुए env (add to .env: NEXT_PUBLIC_API_BASE=https://laravel-server.lab.audasmedia.com.au) const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? ""; async function http(path: string, init?: RequestInit): Promise { const res = await fetch(`${API_BASE}${path}`, { method: "GET", headers: { "Accept": "application/json", ...(init?.headers ?? {}) }, cache: "no-store", ...init, }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`); } const text = await res.text(); return (text ? JSON.parse(text) : null) as T; } export async function postTelemetry(imei: string, body: TelemetryPost) { const validatedBody = telemetrySchema.parse(body); return http<{ ok: true }>(`/api/device/${imei}/telemetry`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(validatedBody), }); } export async function getCommands(imei: string, since?: string) { const q = since ? `?since=${encodeURIComponent(since)}` : ""; return http(`/api/device/${imei}/commands${q}`); } export async function postReceipt(imei: string, body: CommandReceiptPost) { const validatedBody = receiptSchema.parse(body); return http<{ ok: true }>(`/api/device/${imei}/command-receipts`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(validatedBody), }); } // Optional: Get latest GPS (adjust if your endpoint is /api/gps/latest-any) export async function getLatestGPS(imei: string) { return http<{ lat: number; lng: number; /* other fields */ }>(`/api/gps/latest-any?imei=${imei}`); }