perf(inbox): cache de avatares no Wasabi e IndexedDB
Solução 3 — Wasabi:
- Após download do CDN do WhatsApp, faz upload fire-and-forget para
Wasabi com path determinístico (avatars/{tenant}/{instance}/{jid}.jpg)
- Armazena o path relativo em contact.avatarUrl no banco
- Na próxima requisição, serve bytes direto do Wasabi sem tocar no CDN do WA
- Adiciona customPath em StorageUploadPayload e getBuffer() na interface
StorageProviderInterface/StorageProviderRegistry e plugin
Solução 4 — IndexedDB:
- Backend expõe avatarVersion (MD5 curto do avatarUrl) no response /api/chats
- Campo propagado por chatStore → chatToLegacy → NewWhatsChat
- Hook useAvatarCache (IndexedDB nativo, sem deps) armazena dataUrl do avatar
com chave jid:version — invalida automaticamente quando o avatar muda no banco
- Avatar.tsx serve do IndexedDB antes de disparar qualquer request HTTP;
converte via canvas e persiste no IndexedDB na primeira carga bem-sucedida
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,8 @@ function chatToLegacy(c: ReturnType<typeof useChatStore.getState>['chats'][0]):
|
||||
? getAvatarProxyUrl({ instance_name: c.instanceId, remote_jid: c.jid }, 'contact')
|
||||
: null
|
||||
|
||||
const avatar_version: string | null = c.contactAvatarVersion ?? null
|
||||
|
||||
return {
|
||||
id: c.id as any,
|
||||
instance_name: c.instanceId,
|
||||
@@ -49,6 +51,7 @@ function chatToLegacy(c: ReturnType<typeof useChatStore.getState>['chats'][0]):
|
||||
phone: formattedPhone,
|
||||
lead_name: c.contactName,
|
||||
avatar_url,
|
||||
avatar_version,
|
||||
bio: isGroup ? 'Detalhes do Grupo' : (formattedPhone || 'Clique para informações'),
|
||||
displayName,
|
||||
subject: c.protocolNumber ? `#${c.protocolNumber}` : (isGroup ? null : formattedPhone),
|
||||
|
||||
Reference in New Issue
Block a user