@adatechnology/conversations-ui 0.1.0-rc.3 → 0.1.0-rc.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/chunk-DXPSPUWF.js +110 -0
  2. package/dist/chunk-GY472G6E.js +2316 -0
  3. package/dist/{chunk-OGRRHQQW.js → chunk-WCBDXZ3X.js} +68 -4
  4. package/dist/flows/index.d.ts +311 -4
  5. package/dist/flows/index.js +1322 -55
  6. package/dist/index.d.ts +1074 -42
  7. package/dist/index.js +3571 -742
  8. package/dist/preview/index.d.ts +328 -8
  9. package/dist/preview/index.js +902 -115
  10. package/dist/styles.css +819 -0
  11. package/dist/types-De5aN-E_.d.ts +502 -0
  12. package/package.json +3 -3
  13. package/src/AudioPlayer.tsx +8 -0
  14. package/src/AudioRecorderButton.test.tsx +30 -0
  15. package/src/AudioRecorderButton.tsx +248 -0
  16. package/src/AudioTranscription.test.tsx +115 -0
  17. package/src/AudioTranscription.tsx +252 -0
  18. package/src/Avatar.tsx +14 -3
  19. package/src/ConversationContextPanel.tsx +218 -44
  20. package/src/ConversationDocumentsPanel.tsx +347 -24
  21. package/src/ConversationHeader.test.tsx +66 -0
  22. package/src/ConversationHeader.tsx +163 -45
  23. package/src/ConversationListItem.tsx +19 -2
  24. package/src/ConversationLocalesProvider.tsx +42 -0
  25. package/src/ConversationRow.tsx +31 -7
  26. package/src/DocumentsLibrary.tsx +382 -0
  27. package/src/EmojiPicker.tsx +70 -55
  28. package/src/FileIcon.test.ts +83 -0
  29. package/src/FileIcon.tsx +88 -11
  30. package/src/InteractiveMessage.test.tsx +41 -0
  31. package/src/InteractiveMessage.tsx +146 -0
  32. package/src/Lightbox.tsx +18 -3
  33. package/src/MediaRenderer.tsx +98 -22
  34. package/src/MessageBubble.test.tsx +41 -0
  35. package/src/MessageBubble.tsx +75 -6
  36. package/src/MessageComposer.test.tsx +35 -0
  37. package/src/MessageComposer.tsx +155 -19
  38. package/src/RichMessageComposer.test.tsx +113 -0
  39. package/src/RichMessageComposer.tsx +551 -0
  40. package/src/SimpleEmojiPicker.tsx +5 -3
  41. package/src/StatusTicks.tsx +1 -1
  42. package/src/Toast.tsx +4 -0
  43. package/src/Tooltip.test.ts +42 -0
  44. package/src/Tooltip.tsx +164 -0
  45. package/src/Wallpaper.test.tsx +21 -0
  46. package/src/Wallpaper.tsx +67 -7
  47. package/src/WhatsAppMessageEditor.tsx +28 -4
  48. package/src/WindowExpiredNotice.tsx +12 -4
  49. package/src/audioRecorderFormat.test.ts +67 -0
  50. package/src/buildOutput.test.ts +79 -0
  51. package/src/composer.constant.ts +33 -0
  52. package/src/conversationTranscript.test.ts +57 -0
  53. package/src/conversationTranscript.ts +29 -4
  54. package/src/conversationWindow.ts +7 -5
  55. package/src/documentTypeLabel.test.ts +57 -0
  56. package/src/documents/DocumentsWorkspace.tsx +543 -0
  57. package/src/documents/index.ts +8 -0
  58. package/src/documents/labels.ts +92 -0
  59. package/src/emojiCatalog.test.ts +35 -0
  60. package/src/emojiCatalog.ts +189 -0
  61. package/src/flows/FlowGroupHeader.tsx +12 -2
  62. package/src/flows/FlowMapCanvas.tsx +15 -12
  63. package/src/flows/FlowMapNode.tsx +4 -1
  64. package/src/flows/FlowNodeCard.tsx +35 -8
  65. package/src/flows/FlowNodePanel.tsx +149 -38
  66. package/src/flows/FlowPalette.tsx +13 -3
  67. package/src/flows/FlowPortalNode.tsx +1 -1
  68. package/src/flows/FlowWhatsAppPreview.tsx +14 -3
  69. package/src/flows/FlowsWorkspace.tsx +1003 -0
  70. package/src/flows/flowCanvasModel.test.ts +293 -0
  71. package/src/flows/flowCanvasModel.ts +342 -0
  72. package/src/flows/flowEditorOps.test.ts +241 -0
  73. package/src/flows/flowEditorOps.ts +177 -0
  74. package/src/flows/flowGraph.ts +6 -6
  75. package/src/flows/index.ts +40 -1
  76. package/src/flows/labels.ts +141 -0
  77. package/src/flows/workspaceContract.test.ts +95 -0
  78. package/src/hooks/useContainerWidth.ts +35 -0
  79. package/src/hooks/useConversationActions.ts +56 -0
  80. package/src/hooks/useConversationDocuments.ts +11 -7
  81. package/src/hooks/useConversationList.ts +15 -9
  82. package/src/hooks/useConversationMessages.ts +2 -2
  83. package/src/hooks/useConversationRealtime.ts +10 -8
  84. package/src/hooks/useScrollToLatestMessage.ts +127 -0
  85. package/src/hooks/useUrlFilterState.ts +107 -0
  86. package/src/icon.constant.ts +12 -0
  87. package/src/index.ts +114 -13
  88. package/src/lib/cn.test.ts +29 -0
  89. package/src/lib/composer-formatting.test.ts +78 -0
  90. package/src/lib/composer-formatting.ts +145 -0
  91. package/src/lib/createMediaUrlResolver.ts +33 -0
  92. package/src/lib/paginated.test.ts +33 -0
  93. package/src/lib/paginated.ts +26 -0
  94. package/src/lib/whatsapp-formatting.test.tsx +37 -0
  95. package/src/lib/whatsapp-formatting.tsx +28 -3
  96. package/src/listing/index.tsx +202 -0
  97. package/src/pagination.constant.ts +10 -0
  98. package/src/preview/ConversationPreview.tsx +199 -13
  99. package/src/preview/ConversationSimulatorPanel.test.tsx +55 -0
  100. package/src/preview/ConversationSimulatorPanel.tsx +89 -0
  101. package/src/preview/MediaTypesPreview.tsx +87 -0
  102. package/src/preview/conversationPreviewFailures.test.ts +64 -0
  103. package/src/preview/createMockConversationsApi.ts +175 -15
  104. package/src/preview/createPreviewBridgeClient.test.ts +92 -0
  105. package/src/preview/createPreviewBridgeClient.ts +124 -0
  106. package/src/preview/createPreviewMediaUploader.ts +82 -0
  107. package/src/preview/createPreviewWebhookClient.test.ts +96 -0
  108. package/src/preview/createPreviewWebhookClient.ts +127 -4
  109. package/src/preview/index.ts +33 -3
  110. package/src/preview/mediaTypeOf.test.ts +15 -0
  111. package/src/preview/mockDocumentsSearch.test.ts +57 -0
  112. package/src/preview/preview.test.ts +5 -3
  113. package/src/preview/previewFileSamples.test.ts +151 -0
  114. package/src/preview/previewFileSamples.ts +74 -0
  115. package/src/preview/previewFixtures.ts +288 -1
  116. package/src/preview/previewMediaSource.test.ts +62 -0
  117. package/src/preview/previewMediaSource.ts +91 -0
  118. package/src/preview/previewMediaUploader.test.ts +61 -0
  119. package/src/providers/ConversationsProvider.tsx +8 -6
  120. package/src/providers/types.ts +185 -10
  121. package/src/quickReply.test.ts +58 -0
  122. package/src/settings/MessagesWorkspace.tsx +468 -0
  123. package/src/settings/TopicsForm.tsx +2 -0
  124. package/src/settings/TranscriptionSettingsForm.test.tsx +81 -0
  125. package/src/settings/TranscriptionSettingsForm.tsx +190 -0
  126. package/src/settings/WelcomeFarewellForm.tsx +1 -0
  127. package/src/settings/WhatsAppCreateTemplateForm.tsx +4 -1
  128. package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
  129. package/src/settings/WhatsAppTemplatesSettings.tsx +9 -1
  130. package/src/styles.css +783 -0
  131. package/src/types.ts +64 -1
  132. package/src/useWaitingNotifications.ts +74 -29
  133. package/src/workspace/BulkTemplateModal.tsx +132 -0
  134. package/src/workspace/ConversationPane.tsx +432 -0
  135. package/src/workspace/ConversationsInboxList.tsx +194 -0
  136. package/src/workspace/ConversationsWorkspace.tsx +346 -0
  137. package/src/workspace/index.ts +12 -0
  138. package/src/workspace/labels.test.ts +17 -0
  139. package/src/workspace/labels.ts +85 -0
  140. package/src/workspace/useConversationsInbox.ts +332 -0
  141. package/dist/chunk-N7B24WYD.js +0 -719
  142. package/dist/chunk-NV2RZ5KT.js +0 -56
  143. package/dist/types-C0PtaO7S.d.ts +0 -207
@@ -1,6 +1,9 @@
1
- import { M as MessagePayload, i as ConversationSummary, h as ConversationEventSource, j as ConversationsApi, S as SSEProvider } from '../types-C0PtaO7S.js';
1
+ import { G as MessagePayload, o as ConversationSummary, m as ConversationEventSource, q as ConversationsApi, L as ListConversationsParams, n as ConversationPage, S as SSEProvider, k as ConversationDocument, N as ResolveMediaUrl } from '../types-De5aN-E_.js';
2
+ export { A as AudioRecorderButton, a as AudioRecorderButtonLabels, b as AudioRecorderButtonProps, D as DEFAULT_AUDIO_RECORDER_BUTTON_LABELS } from '../types-De5aN-E_.js';
2
3
  import * as react from 'react';
3
- import { InteractiveReplyOption } from '@adatechnology/meta-whatsapp-contracts/testing';
4
+ import { ReactNode } from 'react';
5
+ import { InteractiveReplyOption, InboundMediaType } from '@adatechnology/meta-whatsapp-contracts/testing';
6
+ export { PREVIEW_MEDIA_ID_PREFIX } from '@adatechnology/meta-whatsapp-contracts';
4
7
 
5
8
  /**
6
9
  * Estado em memória que alimenta o preview de atendimento humano. Mock de API e mock de SSE
@@ -81,7 +84,15 @@ type CreateMockConversationsApiParams = {
81
84
  readonly latencyMs?: number;
82
85
  readonly agentName?: string;
83
86
  };
84
- declare function createMockConversationsApi(params: CreateMockConversationsApiParams): ConversationsApi;
87
+ /**
88
+ * O mock satisfaz `ConversationsApi`, mas com o retorno de `fetchConversations` ESTREITADO para a
89
+ * forma paginada. Sem isto o contrato — que aceita array ou página — obrigaria todo consumidor do
90
+ * preview a desempacotar uma união que aqui nunca varia.
91
+ */
92
+ type MockConversationsApi = Omit<ConversationsApi, 'fetchConversations'> & {
93
+ fetchConversations(params?: ListConversationsParams): Promise<ConversationPage>;
94
+ };
95
+ declare function createMockConversationsApi(params: CreateMockConversationsApiParams): MockConversationsApi;
85
96
 
86
97
  /**
87
98
  * `SSEProvider` servido pelo store em memória. Mesmo mapeamento de canal do servidor
@@ -101,6 +112,53 @@ declare function createMockSSEProvider(params: CreateMockSSEProviderParams): SSE
101
112
 
102
113
  declare const PREVIEW_CONVERSATIONS: readonly ConversationSummary[];
103
114
  declare const PREVIEW_MESSAGES: Readonly<Record<string, readonly MessagePayload[]>>;
115
+ declare const PREVIEW_DOCUMENTS: Readonly<Record<string, readonly ConversationDocument[]>>;
116
+
117
+ /**
118
+ * Entrega ao simulador o `uploadMedia` que ele precisa para desenhar o microfone.
119
+ *
120
+ * O `ConversationPreview` esconde o gravador sem esta função, e com razão: microfone que grava sem
121
+ * ter onde guardar o arquivo faz o operador falar para o vazio. O que faltava era montar isto —
122
+ * lê o `File`, manda para a rota do host, devolve o `mediaId` prefixado que o webhook referencia.
123
+ *
124
+ * Fica no pacote porque a parte que erra é sempre a mesma em todo produto: converter o binário sem
125
+ * estourar a pilha e marcar o id com o prefixo que o backend reconhece. O que muda por produto é só
126
+ * a rota e o cliente HTTP — e é exatamente isso que entra por parâmetro.
127
+ */
128
+ /**
129
+ * Do `contracts`, que este pacote já consome — não uma cópia.
130
+ *
131
+ * A convenção tem duas pontas (o front gera o id, o backend resolve) e a versão anterior disso vivia
132
+ * duplicada em dois pacotes de um produto, cada cópia com um comentário pedindo para não divergir.
133
+ * Contrato compartilhado é o que o `contracts` existe para guardar.
134
+ */
135
+
136
+ type PreviewUploadedMedia$1 = {
137
+ readonly mediaId: string;
138
+ readonly mimeType?: string;
139
+ readonly filename?: string;
140
+ };
141
+ type PreviewMediaUploadRequest = {
142
+ readonly base64: string;
143
+ readonly mimeType: string;
144
+ readonly filename: string;
145
+ };
146
+ type CreatePreviewMediaUploaderParams = {
147
+ /**
148
+ * Envia o arquivo à rota do host e devolve o `uploadId` (sem prefixo) que o backend gerou.
149
+ *
150
+ * Recebe a função inteira, e não uma URL, porque autenticação varia: uma instalação assina com
151
+ * HMAC, outra manda token de admin, outra usa cookie de sessão. Pedir a URL obrigaria o pacote a
152
+ * escolher por elas.
153
+ */
154
+ readonly upload: (request: PreviewMediaUploadRequest) => Promise<{
155
+ uploadId: string;
156
+ }>;
157
+ /** Nome usado quando o gravador entrega o áudio sem nome próprio. */
158
+ readonly fallbackFilename?: string;
159
+ readonly fallbackMimeType?: string;
160
+ };
161
+ declare function createPreviewMediaUploader(params: CreatePreviewMediaUploaderParams): (file: File) => Promise<PreviewUploadedMedia$1>;
104
162
 
105
163
  /**
106
164
  * Cliente que entrega mensagens do preview no webhook real, assinadas com HMAC — a mesma validação
@@ -110,9 +168,14 @@ declare const PREVIEW_MESSAGES: Readonly<Record<string, readonly MessagePayload[
110
168
  * Assina com WebCrypto porque `node:crypto` não existe no navegador. Os builders vêm dos contratos
111
169
  * (isomórficos) justamente para que o mesmo payload seja montado nos dois runtimes.
112
170
  *
113
- * ⚠️ Isto carrega o app secret de DESENVOLVIMENTO no bundle. Só existe para o docker local, e
114
- * `assertPreviewEnvironment` recusa rodar em produção — um segredo de dev vazado é irrelevante,
115
- * mas o hábito de embarcar segredo em frontend não é.
171
+ * ⚠️ SOMENTE EXECUÇÃO LOCAL. Isto carrega o app secret no bundle, e bundle é público onde quer que
172
+ * seja servido — em qualquer ambiente com URL acessível (homologação inclusive) usar esta fábrica
173
+ * equivale a publicar o segredo, e quem o tiver forja webhooks válidos daquele app da Meta: injeta
174
+ * mensagem de qualquer número e dispara os fluxos. `assertPreviewEnvironment` barra produção, mas
175
+ * homologação passaria, então a barreira não basta.
176
+ *
177
+ * Para qualquer ambiente publicado use `createPreviewBridgeClient`: o navegador manda a intenção e
178
+ * o servidor assina com o segredo que ele já tem.
116
179
  */
117
180
 
118
181
  type PreviewWebhookClient = {
@@ -120,14 +183,52 @@ type PreviewWebhookClient = {
120
183
  sendButtonReply(reply: InteractiveReplyOption): Promise<void>;
121
184
  sendListReply(reply: InteractiveReplyOption): Promise<void>;
122
185
  sendAudio(mediaId: string): Promise<void>;
186
+ sendMedia(params: SendPreviewMediaParams): Promise<void>;
187
+ /**
188
+ * Guarda um arquivo gravado e devolve o `mediaId` já prefixado, pronto para `sendMedia`.
189
+ *
190
+ * Existe no cliente, e não como prop de quem monta a tela, porque isto é exatamente o que ele já
191
+ * sabe fazer: falar com ESTE host usando ESTE segredo. Enquanto era responsabilidade do produto,
192
+ * o resultado prático foi um produto com microfone no simulador e outro sem — não por decisão,
193
+ * por esquecimento. Cliente montado, microfone na tela.
194
+ *
195
+ * Opcional porque o cliente-ponte só consegue oferecer isto quando sabe a rota de mídia (ou quando
196
+ * o host injeta a função): sem destino, gravar áudio seria falar para o vazio, e aí a tela
197
+ * corretamente não desenha o gravador.
198
+ */
199
+ uploadMedia?(file: File): Promise<PreviewUploadedMedia$1>;
200
+ };
201
+ type SendPreviewMediaParams = {
202
+ readonly mediaType: InboundMediaType;
203
+ /**
204
+ * Id que o host já usa para buscar o arquivo. Não é bytes: o webhook da Meta entrega mídia por
205
+ * referência, e o consumidor baixa depois — mandar base64 aqui simularia um payload que a Meta
206
+ * nunca produz, e o caminho testado deixaria de ser o de produção.
207
+ */
208
+ readonly mediaId: string;
209
+ readonly mimeType?: string;
210
+ readonly filename?: string;
211
+ readonly caption?: string;
123
212
  };
124
213
  type CreatePreviewWebhookClientParams = {
125
214
  readonly webhookUrl: string;
126
215
  readonly appSecret: string;
127
216
  readonly from: string;
128
217
  readonly phoneNumberId?: string;
218
+ /**
219
+ * Rota que guarda o áudio gravado. Por padrão, `/v1/preview/media` na mesma origem do webhook.
220
+ *
221
+ * O padrão cobre o caso normal — as duas rotas são do mesmo servidor — e a prop existe para quem
222
+ * publica a API em outro host ou versiona o caminho.
223
+ */
224
+ readonly mediaUploadUrl?: string;
129
225
  readonly fetchImplementation?: typeof fetch;
130
226
  };
227
+ /** Falha da rota de upload, separada da do webhook: os dois lados quebram por motivos diferentes. */
228
+ declare class PreviewMediaUploadRejectedError extends Error {
229
+ readonly status: number;
230
+ constructor(status: number);
231
+ }
131
232
  declare class PreviewInProductionError extends Error {
132
233
  constructor();
133
234
  }
@@ -140,6 +241,30 @@ declare class PreviewWebhookRejectedError extends Error {
140
241
  * que um que se recusa a montar.
141
242
  */
142
243
  declare function assertPreviewEnvironment(isProduction: boolean): void;
244
+ /**
245
+ * Assina um texto qualquer com o app secret, no mesmo formato do header da Meta.
246
+ *
247
+ * Exportada porque o preview precisa provar identidade em MAIS de um lugar: além de entregar a
248
+ * mensagem no webhook, ele lê o transcript de volta — e ler pela API de admin exigia uma sessão que
249
+ * a aba do simulador não tem. Assinar a leitura com o segredo que ele já carrega resolve sem token
250
+ * de admin e sem rota aberta.
251
+ */
252
+ declare function signPreviewPayload(params: {
253
+ rawBody: string;
254
+ appSecret: string;
255
+ }): Promise<string>;
256
+ declare const DEFAULT_MEDIA_UPLOAD_PATH = "/v1/preview/media";
257
+ /**
258
+ * O POST de mídia, sem a parte de assinatura — para os dois clientes usarem o mesmo caminho.
259
+ *
260
+ * O cliente-ponte autentica por sessão e o de webhook por HMAC; o que não muda é a rota, o formato
261
+ * do corpo e a leitura do `uploadId`. Duas cópias disso é como o prefixo de mídia divergiu antes.
262
+ */
263
+ declare function createPreviewMediaPoster(params: {
264
+ readonly url: string;
265
+ readonly headers?: (mimeType: string) => Promise<Readonly<Record<string, string>>>;
266
+ readonly fetchImplementation?: typeof fetch;
267
+ }): (file: File) => Promise<PreviewUploadedMedia$1>;
143
268
  declare function createPreviewWebhookClient(params: CreatePreviewWebhookClientParams): PreviewWebhookClient;
144
269
 
145
270
  type ConversationPreviewProps = {
@@ -148,8 +273,123 @@ type ConversationPreviewProps = {
148
273
  conversationId: string;
149
274
  loadMessages: (conversationId: string) => Promise<MessagePayload[]>;
150
275
  placeholder?: string;
276
+ /**
277
+ * Recarrega o transcript a cada N ms. Serve a host SEM stream: a resposta do bot é assíncrona, e
278
+ * sem SSE nem polling ela só apareceria no próximo envio — o sintoma é "às vezes ele não
279
+ * responde". Ausente, não faz polling (host com SSE não precisa).
280
+ */
281
+ pollIntervalMs?: number;
282
+ /**
283
+ * Como transformar um arquivo do disco (ou o áudio gravado) na referência que o webhook carrega.
284
+ * O caminho da Meta entrega mídia por `id`, e quem sabe hospedar o arquivo é o host — a SDK não
285
+ * inventa um endpoint de upload. Ausente, o compositor não oferece anexo nem gravação: melhor um
286
+ * botão que não existe do que um que falha ao ser tocado.
287
+ */
288
+ /** Destino alternativo do áudio gravado. Sem isto, usa o do próprio `client`. */
289
+ uploadMedia?: (file: File) => Promise<PreviewUploadedMedia>;
290
+ };
291
+ type PreviewUploadedMedia = {
292
+ readonly mediaId: string;
293
+ readonly mimeType?: string;
294
+ readonly filename?: string;
151
295
  };
152
- declare function ConversationPreview({ client, sse, conversationId, loadMessages, placeholder, }: ConversationPreviewProps): react.JSX.Element;
296
+ /** Deriva o tipo de mídia do WhatsApp a partir do MIME do arquivo escolhido. */
297
+ declare function mediaTypeOf(mimeType: string): SendPreviewMediaParams['mediaType'];
298
+ declare function ConversationPreview({ client, sse, conversationId, loadMessages, placeholder, pollIntervalMs, uploadMedia, }: ConversationPreviewProps): react.JSX.Element;
299
+
300
+ type ConversationSimulatorPanelLabels = {
301
+ readonly title: string;
302
+ /** Complementa o telefone no subtítulo, explicando para onde a mensagem realmente vai. */
303
+ readonly destinationHint: string;
304
+ readonly close: string;
305
+ readonly placeholder: string;
306
+ };
307
+ declare const DEFAULT_CONVERSATION_SIMULATOR_PANEL_LABELS: ConversationSimulatorPanelLabels;
308
+ type ConversationSimulatorPanelProps = Omit<ConversationPreviewProps, 'placeholder'> & {
309
+ readonly onClose: () => void;
310
+ /**
311
+ * Telefone já formatado para leitura. É o host que formata: máscara de telefone é convenção
312
+ * regional, e o pacote não tem como saber a do produto.
313
+ */
314
+ readonly displayNumber?: string;
315
+ readonly labels?: Partial<ConversationSimulatorPanelLabels>;
316
+ /** Ações extras no cabeçalho — roteiro automático, limpar conversa, trocar de contato. */
317
+ readonly headerActions?: ReactNode;
318
+ };
319
+ declare function ConversationSimulatorPanel({ onClose, displayNumber, labels, headerActions, ...previewProps }: ConversationSimulatorPanelProps): react.JSX.Element;
320
+
321
+ /**
322
+ * Cliente do preview que NÃO carrega segredo: em vez de montar e assinar o payload da Meta no
323
+ * navegador, manda um comando semântico (`{ kind: 'text', text }`) para uma rota do próprio host,
324
+ * autenticada pela sessão que o painel já tem. Quem monta o payload e assina é o servidor, com o
325
+ * app secret que nunca sai de lá.
326
+ *
327
+ * Por que esta fábrica existe ao lado de `createPreviewWebhookClient`: assinar no navegador exige o
328
+ * app secret dentro do bundle, e bundle é público por definição — em qualquer ambiente com URL
329
+ * acessível isso é o mesmo que publicar o segredo. Com o segredo vazado, qualquer um forja webhooks
330
+ * válidos daquele app: injeta mensagens de qualquer número e dispara os fluxos. `createPreviewWebhook
331
+ * Client` continua servindo para execução puramente local (docker de dev, onde o bundle não é
332
+ * servido para ninguém); para qualquer ambiente publicado, a ponte é o caminho.
333
+ *
334
+ * O pacote não decide autenticação: o host injeta `sendCommand` (ou `headers` + `fetchImplementation`),
335
+ * porque token, cookie e cabeçalho de sessão são do produto, não da biblioteca.
336
+ */
337
+
338
+ /**
339
+ * Comando semântico entregue ao host. É deliberadamente o QUE o cliente fez, não o payload da Meta:
340
+ * se o navegador mandasse o payload pronto, a rota viraria um injetor de webhook arbitrário para
341
+ * quem tivesse sessão. Mandando a intenção, o servidor é quem escolhe a forma.
342
+ */
343
+ type PreviewInboundCommand = {
344
+ readonly kind: 'text';
345
+ readonly from: string;
346
+ readonly text: string;
347
+ } | {
348
+ readonly kind: 'buttonReply';
349
+ readonly from: string;
350
+ readonly reply: InteractiveReplyOption;
351
+ } | {
352
+ readonly kind: 'listReply';
353
+ readonly from: string;
354
+ readonly reply: InteractiveReplyOption;
355
+ } | {
356
+ readonly kind: 'audio';
357
+ readonly from: string;
358
+ readonly mediaId: string;
359
+ } | ({
360
+ readonly kind: 'media';
361
+ readonly from: string;
362
+ } & SendPreviewMediaParams);
363
+ type SendPreviewInboundCommand = (command: PreviewInboundCommand) => Promise<void>;
364
+ declare class PreviewBridgeRejectedError extends Error {
365
+ readonly status: number;
366
+ constructor(status: number);
367
+ }
368
+ type CreatePreviewBridgeClientParams = {
369
+ readonly from: string;
370
+ /**
371
+ * Entrega o comando. Use quando o host já tem um cliente HTTP com sessão, interceptors e refresh
372
+ * de token — reimplementar isso aqui só duplicaria a autenticação do produto.
373
+ */
374
+ readonly sendCommand?: SendPreviewInboundCommand;
375
+ /** Alternativa a `sendCommand` para hosts sem cliente HTTP próprio. */
376
+ readonly endpointUrl?: string;
377
+ readonly headers?: Readonly<Record<string, string>>;
378
+ readonly fetchImplementation?: typeof fetch;
379
+ /**
380
+ * Rota que guarda o áudio gravado. Por padrão, `/v1/preview/media` na origem do `endpointUrl`.
381
+ *
382
+ * Aqui não há assinatura a calcular: a ponte existe justamente para não ter segredo no navegador,
383
+ * e a rota é protegida pela sessão do painel — os mesmos `headers` do comando valem para o upload.
384
+ */
385
+ readonly mediaUploadUrl?: string;
386
+ /**
387
+ * Substitui o upload embutido. Necessário para host que só passa `sendCommand`: sem `endpointUrl`
388
+ * não há origem a derivar, e sem destino o gravador não é desenhado.
389
+ */
390
+ readonly uploadMedia?: (file: File) => Promise<PreviewUploadedMedia$1>;
391
+ };
392
+ declare function createPreviewBridgeClient(params: CreatePreviewBridgeClientParams): PreviewWebhookClient;
153
393
 
154
394
  /**
155
395
  * Roteiro que mantém o preview vivo: sem tráfego chegando, a inbox é uma tela estática e as
@@ -169,4 +409,84 @@ type StartPreviewScriptParams = {
169
409
  };
170
410
  declare function startPreviewScript(params: StartPreviewScriptParams): () => void;
171
411
 
172
- export { type AppendMessageParams, ConversationPreview, type ConversationPreviewProps, type CreateMockConversationsApiParams, type CreateMockSSEProviderParams, type CreatePreviewStoreParams, type CreatePreviewWebhookClientParams, DEFAULT_PREVIEW_SCRIPT, GLOBAL_CHANNEL, type ListConversationsFilters, type MockEventSource, PREVIEW_CONVERSATIONS, PREVIEW_MESSAGES, type PreviewEmission, PreviewInProductionError, type PreviewScriptStep, type PreviewStore, type PreviewStoreListener, type PreviewWebhookClient, PreviewWebhookRejectedError, type SetModeParams, type StartPreviewScriptParams, assertPreviewEnvironment, conversationChannel, createMockConversationsApi, createMockEventSource, createMockSSEProvider, createPreviewStore, createPreviewWebhookClient, startPreviewScript };
412
+ /**
413
+ * Bytes de verdade para o preview abrir.
414
+ *
415
+ * O mock antes devolvia a MESMA imagem PNG para qualquer documento, então clicar em "visualizar" num
416
+ * PDF entregava um PNG rotulado `application/pdf` e o leitor dizia que o arquivo era inválido. Cada
417
+ * amostra aqui é um arquivo mínimo porém legítimo do seu tipo: as de mídia foram geradas com ffmpeg
418
+ * e conferidas com ffprobe, o PDF tem xref/startxref/%%EOF, e os pacotes Office são zips com as
419
+ * partes obrigatórias (`[Content_Types].xml`, `_rels/.rels`, o documento).
420
+ *
421
+ * Não há amostra de `audio/amr`, `video/3gp` nem dos formatos binários legados do Office
422
+ * (`application/msword`, `application/vnd.ms-excel`, `application/vnd.ms-powerpoint`): não há
423
+ * encoder para eles nesta máquina e forjar OLE2 à mão daria arquivo corrompido — exatamente o que
424
+ * este módulo existe para evitar. Esses caem no texto explicativo de `resolvePreviewFileSample`,
425
+ * que abre sem erro e diz o que é.
426
+ *
427
+ * GERADO — não editar à mão.
428
+ */
429
+ declare const PREVIEW_FILE_SAMPLES: Readonly<Record<string, string>>;
430
+ /**
431
+ * A data URL que o preview abre para um documento.
432
+ *
433
+ * Ordem: tipo exato → família (`audio/amr` toca como mp3, `video/3gp` como mp4) → nota em texto.
434
+ * A nota fecha o caso dos tipos sem amostra: abre num leitor de texto e explica, em vez de baixar
435
+ * um binário quebrado com extensão de Word.
436
+ */
437
+ declare function resolvePreviewFileSample(mimeType: string | undefined, filename?: string): string;
438
+
439
+ /**
440
+ * Como o preview entrega mídia para a UI abrir.
441
+ *
442
+ * Separado de `previewFileSamples` (que é gerado) porque aqui está a parte que depende do navegador:
443
+ * **blob URL, não data URL**. O Chrome bloqueia navegação de topo para `data:` desde a v60, então
444
+ * `window.open(dataUrl)` — que é o que os botões "visualizar" e "baixar" fazem — abre aba em branco
445
+ * mesmo com bytes perfeitamente válidos. Em `src` de `<img>`/`<video>` a data URL funcionaria; no
446
+ * `window.open` não, e o mesmo `getDocumentUrl` alimenta os dois.
447
+ */
448
+
449
+ /** URL que o preview pode abrir em aba nova. Cai na data URL fora do navegador (teste, SSR). */
450
+ declare function previewFileUrl(mimeType: string | undefined, filename?: string): string;
451
+ /**
452
+ * A mesma amostra em base64 cru, como o proxy de mídia do backend a devolveria.
453
+ *
454
+ * Existe porque `getMediaProxyUrl` é o caminho da mídia AINDA NÃO ingerida (só existe o id na Meta),
455
+ * e o contrato pede `{ mimeType, data }` — não URL. Sem isto o mock devolvia o PNG 1x1 para
456
+ * qualquer id, e vídeo e áudio da thread apareciam quebrados apesar de haver amostra válida.
457
+ */
458
+ declare function previewFileBase64(mimeType: string | undefined, filename?: string): {
459
+ mimeType: string;
460
+ data: string;
461
+ };
462
+ /**
463
+ * O `onResolveMediaUrl` que o `MessageBubble` espera.
464
+ *
465
+ * Sem ele, foto, vídeo e áudio da thread ficam parados no placeholder para sempre — o
466
+ * `MediaRenderer` só resolve `uploadId`/`mediaId` por esta porta, de propósito, para o pacote nunca
467
+ * chamar endpoint fixo. O preview não tinha resolvedor nenhum, então nenhuma mídia carregava.
468
+ */
469
+ declare function createPreviewMediaResolver(): ResolveMediaUrl;
470
+
471
+ /**
472
+ * Bancada de teste manual de mídia — montável em uma linha por qualquer projeto que adote o SDK.
473
+ *
474
+ * Existe porque o defeito que ela pega não é pegável por teste automatizado: "o PDF abre?" depende
475
+ * do leitor do navegador, "o vídeo toca?" do decodificador, e "a aba abre?" da política do Chrome
476
+ * sobre `data:` URL. Teste unitário confere bytes; só o olho confere que o arquivo abre. Sem uma
477
+ * superfície pronta no pacote, cada projeto teria de montar a sua — e, na prática, nenhum montava.
478
+ *
479
+ * Traz o próprio store, o próprio mock e o próprio provider: o host não injeta nada. E não passa
480
+ * `onResolveMediaUrl` em lugar nenhum de propósito — é o `MessageBubble` resolvendo mídia pelo
481
+ * `ConversationsApi` do contexto, então se essa resolução automática quebrar, esta tela mostra.
482
+ */
483
+ /** A conversa do fixture que carrega uma mensagem de cada tipo aceito. */
484
+ declare const MEDIA_TYPES_CONVERSATION_ID = "5511944443333";
485
+ type MediaTypesPreviewProps = {
486
+ /** Outra conversa do fixture, se o projeto tiver acrescentado a sua. */
487
+ conversationId?: string;
488
+ className?: string;
489
+ };
490
+ declare function MediaTypesPreview({ conversationId, className, }: MediaTypesPreviewProps): react.JSX.Element;
491
+
492
+ export { type AppendMessageParams, ConversationPreview, type ConversationPreviewProps, ConversationSimulatorPanel, type ConversationSimulatorPanelLabels, type ConversationSimulatorPanelProps, type CreateMockConversationsApiParams, type CreateMockSSEProviderParams, type CreatePreviewBridgeClientParams, type CreatePreviewMediaUploaderParams, type CreatePreviewStoreParams, type CreatePreviewWebhookClientParams, DEFAULT_CONVERSATION_SIMULATOR_PANEL_LABELS, DEFAULT_MEDIA_UPLOAD_PATH, DEFAULT_PREVIEW_SCRIPT, GLOBAL_CHANNEL, type ListConversationsFilters, MEDIA_TYPES_CONVERSATION_ID, MediaTypesPreview, type MediaTypesPreviewProps, type MockEventSource, PREVIEW_CONVERSATIONS, PREVIEW_DOCUMENTS, PREVIEW_FILE_SAMPLES, PREVIEW_MESSAGES, PreviewBridgeRejectedError, type PreviewEmission, PreviewInProductionError, type PreviewInboundCommand, PreviewMediaUploadRejectedError, type PreviewMediaUploadRequest, type PreviewScriptStep, type PreviewStore, type PreviewStoreListener, type PreviewUploadedMedia, type PreviewWebhookClient, PreviewWebhookRejectedError, type SendPreviewInboundCommand, type SendPreviewMediaParams, type SetModeParams, type StartPreviewScriptParams, assertPreviewEnvironment, conversationChannel, createMockConversationsApi, createMockEventSource, createMockSSEProvider, createPreviewBridgeClient, createPreviewMediaPoster, createPreviewMediaResolver, createPreviewMediaUploader, createPreviewStore, createPreviewWebhookClient, mediaTypeOf, previewFileBase64, previewFileUrl, resolvePreviewFileSample, signPreviewPayload, startPreviewScript };