Modelo de datos — Request
Interfaces
OfflineData (raíz)
interface OfflineData {
requestQueue: { [sender: string]: Array<Request> }; // pendientes, agrupadas por sender
removedQueue: { [sender: string]: Array<Request> }; // eliminadas (por error o manualmente)
transactionId: number; // autoincremental global
}
Request (cada operación encolada)
interface Request {
id: number; // transactionId al momento de encolar
api: string; // endpoint relativo (ej: "/agregarlote", "/scouting/scout")
body: string | { [key: string]: any }; // payload, generalmente JSON.stringify(...)
method: ValidMethods; // "POST" | "PUT" | "PUTF" | "PATCH" | "DELETE"
opts: RequestOpts; // headers, params, body (para DELETE)
eventData: { [key: string]: any }; // metadata de UI (msg: código de toast, removeOnFail, etc.)
latestError?: ReqError; // último error HTTP recibido
deleted?: number; // timestamp de eliminación (solo en removedQueue)
attempts: number; // reintentos acumulados
date: number; // Date.now() al momento de encolar
userId: string; // UID del usuario que generó la request
}
RequestOpts
interface RequestOpts {
body?: { [key: string]: any }; // usado en DELETE (HttpClient.delete({body}))
params: { [key: string]: any }; // query params o metadata (ej: uuid, path, mimetype)
headers: { [key: string]: string }; // Content-Type, X-Version (NO incluye Authorization al guardar)
}
ReqError
interface ReqError {
error: any; // copia serializada del error HTTP
timestamp: number; // Date.now() del error
}
ValidMethods
type ValidMethods = 'POST' | 'POSTF' | 'PUT' | 'PUTF' | 'GET' | 'DELETE' | 'PATCH';
Nota:
PUTFes un PUT de archivo (imagen). Lee el archivo del filesystem local, lo convierte a Blob y lo envía como FormData.POSTFestá declarado pero no se usa actualmente.
Ejemplo real de una Request encolada
{
"id": 42,
"api": "/scouting/scout",
"body": "{\"uuid\":\"abc-123\",\"created\":\"2024-01-15T10:30:00-03:00\",\"new_campaign\":{\"field_uuid\":\"field-1\",\"campaign_year\":2024,\"biennial\":false}}",
"method": "POST",
"opts": {
"params": {},
"headers": {
"X-Version": "3.2.0",
"Content-Type": "application/json"
}
},
"eventData": { "msg": 400 },
"attempts": 0,
"date": 1705312200000,
"userId": "user-uuid-123"
}
Notas sobre Authorization
El token no se guarda en opts.headers al momento de encolar (se usa headerService.json() que no incluye Authorization). Al momento de enviar, OfflineHttpService.sendRequest() inyecta el token vigente:
headers.Authorization = `Bearer ${this.userTokenStore.tokens[req.userId]}`;
Esto permite que requests encoladas con tokens vencidos se envíen con el token actualizado.