Users standing at a register saw nothing until the detailed ack, which waits on extraction (10-60s) and reads as a black hole; failures could take minutes longer via the sweep. Now the webhook reacts with a U+2705 checkmark on the sender's own media bubble right after the durable row is persisted, so the 'correctly received' signal lands within seconds. - sendReaction in graph-api: best-effort like mark-read, never throws, no outbound row (a reaction is not a message in the conversation model) - gated on the chat MIME allowlist (moved to lib/chat-mime.ts so tests mocking process-inbound cannot lose it): junk earns M15, no checkmark - no reaction for unknown, muted, or redelivered (23505) messages - detailed M4/M5 combined ack and the one-message-per-burst design are unchanged Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
21 lines
792 B
TypeScript
21 lines
792 B
TypeScript
/**
|
|
* Chat intake accepts what phones actually produce. Narrower than the upload
|
|
* allowlist on purpose: WhatsApp transcodes photos to JPEG, so HEIC never
|
|
* arrives, and everything else gets the M15 nudge.
|
|
*
|
|
* Lives in its own dependency-free module because both the deferred worker
|
|
* (the M15 rejection) and the webhook (the instant checkmark reaction) gate
|
|
* on it, and tests that mock process-inbound must not lose the constant.
|
|
*/
|
|
export const CHAT_ALLOWED_MIME_TYPES: ReadonlySet<string> = new Set([
|
|
'image/jpeg',
|
|
'image/png',
|
|
'image/webp',
|
|
'application/pdf',
|
|
])
|
|
|
|
/** Normalize a raw MIME header value to what the allowlist stores. */
|
|
export function normalizeChatMime(mime: string | null | undefined): string {
|
|
return (mime ?? '').split(';')[0].trim().toLowerCase()
|
|
}
|