@adatechnology/meta-whatsapp-contracts 0.2.0 → 0.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/index.ts","../../src/testing/inboundPayloads.ts"],"sourcesContent":["/**\n * Export separado (`@adatechnology/meta-whatsapp-contracts/testing`): utilitário de\n * desenvolvimento não entra no grafo de import de quem consome os contratos em produção.\n */\n\nexport {\n buildInboundTextPayload,\n buildInboundInteractivePayload,\n buildInboundAudioPayload,\n buildInboundMediaPayload,\n serializeWebhookPayload,\n PREVIEW_PHONE_NUMBER_ID,\n PREVIEW_WABA_ID,\n PREVIEW_DISPLAY_PHONE_NUMBER,\n PREVIEW_AUDIO_MIME_TYPE,\n} from './inboundPayloads'\n\nexport type {\n BuildInboundTextPayloadParams,\n BuildInboundInteractivePayloadParams,\n BuildInboundAudioPayloadParams,\n BuildInboundMediaPayloadParams,\n InboundMediaType,\n InteractiveReplyOption,\n} from './inboundPayloads'\n","/**\n * Builders de payload inbound para exercitar o webhook em desenvolvimento sem um app da Meta\n * credenciado. Moram aqui, e não no módulo, por uma razão de runtime: o preview do navegador\n * precisa montar payloads, e o módulo depende de `node:crypto` — importá-lo do frontend quebraria\n * o bundle. Este pacote só depende de zod, então roda nos dois lados.\n *\n * São construção de payload, não assinatura: assinar depende do runtime (`node:crypto` no\n * servidor, WebCrypto no navegador) e fica com quem tem o segredo.\n *\n * Por que `id` e `timestamp` são novos a cada chamada: o anti-replay do webhook usa o header de\n * assinatura como nonce, e a assinatura é derivada do corpo cru. Dois payloads idênticos geram a\n * mesma assinatura, e a segunda entrega é descartada como duplicata — numa conversa real (\"sim\"\n * duas vezes) isso apareceria como mensagem engolida, sem erro nenhum para investigar.\n */\n\nimport type { WhatsAppMessage, WhatsAppWebhookPayload } from '../webhook.types'\n\n// Valores de dev que espelham o formato dos reais (15 dígitos) sem apontar para nada da Meta.\nexport const PREVIEW_PHONE_NUMBER_ID = '000000000000000'\nexport const PREVIEW_WABA_ID = '000000000000001'\nexport const PREVIEW_DISPLAY_PHONE_NUMBER = '+5511900000000'\n\n// O que a Meta manda para áudio gravado no app; o pipeline de STT depende do mime para decodificar.\nexport const PREVIEW_AUDIO_MIME_TYPE = 'audio/ogg; codecs=opus'\n\ntype InboundEnvelopeParams = {\n readonly from: string\n readonly phoneNumberId?: string\n readonly displayPhoneNumber?: string\n readonly wabaId?: string\n}\n\n// `globalThis.crypto` em vez de `node:crypto`: é o que existe tanto no navegador quanto no Node\n// 19+/Bun, e é o que mantém estes builders utilizáveis pelo preview do navegador.\nfunction generateWamid(): string {\n // Formato real é `wamid.<base64>`. O prefixo importa para quem faz parsing por prefixo; o corpo\n // só precisa ser único por entrega, que é o que mantém a assinatura — e o nonce — distinta.\n const unique = globalThis.crypto.randomUUID().replaceAll('-', '')\n return `wamid.${unique}`\n}\n\nfunction currentTimestamp(): string {\n return Math.floor(Date.now() / 1000).toString()\n}\n\ntype BuildEnvelopeParams = InboundEnvelopeParams & {\n readonly message: WhatsAppMessage\n}\n\nfunction buildEnvelope(params: BuildEnvelopeParams): WhatsAppWebhookPayload {\n return {\n object: 'whatsapp_business_account',\n entry: [\n {\n id: params.wabaId ?? PREVIEW_WABA_ID,\n changes: [\n {\n value: {\n messaging_product: 'whatsapp',\n metadata: {\n display_phone_number: params.displayPhoneNumber ?? PREVIEW_DISPLAY_PHONE_NUMBER,\n phone_number_id: params.phoneNumberId ?? PREVIEW_PHONE_NUMBER_ID,\n },\n messages: [params.message],\n },\n },\n ],\n },\n ],\n }\n}\n\nexport type BuildInboundTextPayloadParams = InboundEnvelopeParams & {\n readonly text: string\n}\n\nexport function buildInboundTextPayload(params: BuildInboundTextPayloadParams): WhatsAppWebhookPayload {\n const { text, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'text',\n text: { body: text },\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type InteractiveReplyOption = {\n readonly id: string\n readonly title: string\n}\n\n// União exclusiva: uma resposta interativa é de botão OU de lista, nunca das duas nem de nenhuma.\n// O tipo torna o erro impossível em vez de validá-lo em runtime.\nexport type BuildInboundInteractivePayloadParams = InboundEnvelopeParams &\n (\n | { readonly buttonReply: InteractiveReplyOption; readonly listReply?: never }\n | { readonly listReply: InteractiveReplyOption; readonly buttonReply?: never }\n )\n\nexport function buildInboundInteractivePayload(params: BuildInboundInteractivePayloadParams): WhatsAppWebhookPayload {\n const { buttonReply, listReply, ...envelope } = params\n\n const interactive = buttonReply\n ? { type: 'button_reply', button_reply: buttonReply }\n : { type: 'list_reply', list_reply: listReply }\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'interactive',\n interactive,\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type BuildInboundAudioPayloadParams = InboundEnvelopeParams & {\n readonly mediaId: string\n readonly mimeType?: string\n}\n\nexport function buildInboundAudioPayload(params: BuildInboundAudioPayloadParams): WhatsAppWebhookPayload {\n const { mediaId, mimeType, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'audio',\n audio: { id: mediaId, mime_type: mimeType ?? PREVIEW_AUDIO_MIME_TYPE },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/** Tipos de mídia que a Meta entrega por `id`, para o consumidor baixar depois. */\nexport type InboundMediaType = 'image' | 'video' | 'audio' | 'document' | 'sticker'\n\nexport type BuildInboundMediaPayloadParams = InboundEnvelopeParams & {\n readonly mediaType: InboundMediaType\n readonly mediaId: string\n readonly mimeType?: string\n readonly filename?: string\n readonly caption?: string\n}\n\n/**\n * Mídia genérica. O bloco vai com o nome do próprio tipo (`image`, `document`, …) porque é assim que\n * a Meta monta o webhook — e é por esse nome que o consumidor localiza o `id` para baixar o arquivo.\n *\n * `filename` só existe em documento e `caption` só em imagem/vídeo/documento; enviar os dois em\n * áudio geraria um payload que a Meta nunca produz, então eles são omitidos quando vazios.\n */\nexport function buildInboundMediaPayload(params: BuildInboundMediaPayloadParams): WhatsAppWebhookPayload {\n const { mediaType, mediaId, mimeType, filename, caption, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: mediaType,\n [mediaType]: {\n id: mediaId,\n ...(mimeType ? { mime_type: mimeType } : {}),\n ...(filename ? { filename } : {}),\n ...(caption ? { caption } : {}),\n },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/**\n * Serializa o payload uma única vez. A validação assina os bytes exatos recebidos: quem reserializa\n * antes de enviar (ou deixa o cliente HTTP serializar o objeto) muda espaçamento/ordem e derruba a\n * assinatura. Assinar e enviar SEMPRE a string devolvida aqui é o contrato.\n */\nexport function serializeWebhookPayload(payload: WhatsAppWebhookPayload): string {\n return JSON.stringify(payload)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;ACkBO,IAAMA,0BAA0B;AAChC,IAAMC,kBAAkB;AACxB,IAAMC,+BAA+B;AAGrC,IAAMC,0BAA0B;AAWvC,SAASC,gBAAAA;AAGP,QAAMC,SAASC,WAAWC,OAAOC,WAAU,EAAGC,WAAW,KAAK,EAAA;AAC9D,SAAO,SAASJ,MAAAA;AAClB;AALSD;AAOT,SAASM,mBAAAA;AACP,SAAOC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA,EAAMC,SAAQ;AAC/C;AAFSL;AAQT,SAASM,cAAcC,QAA2B;AAChD,SAAO;IACLC,QAAQ;IACRC,OAAO;MACL;QACEC,IAAIH,OAAOI,UAAUpB;QACrBqB,SAAS;UACP;YACEC,OAAO;cACLC,mBAAmB;cACnBC,UAAU;gBACRC,sBAAsBT,OAAOU,sBAAsBzB;gBACnD0B,iBAAiBX,OAAOY,iBAAiB7B;cAC3C;cACA8B,UAAU;gBAACb,OAAOc;;YACpB;UACF;;MAEJ;;EAEJ;AACF;AArBSf;AA2BF,SAASgB,wBAAwBf,QAAqC;AAC3E,QAAM,EAAEgB,MAAM,GAAGC,SAAAA,IAAajB;AAE9B,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNH,MAAM;QAAEI,MAAMJ;MAAK;MACnBK,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBsB;AA4BT,SAASO,+BAA+BtB,QAA4C;AACzF,QAAM,EAAEuB,aAAaC,WAAW,GAAGP,SAAAA,IAAajB;AAEhD,QAAMyB,cAAcF,cAChB;IAAEJ,MAAM;IAAgBO,cAAcH;EAAY,IAClD;IAAEJ,MAAM;IAAcQ,YAAYH;EAAU;AAEhD,SAAOzB,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNM;MACAJ,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAjBgB6B;AAwBT,SAASM,yBAAyB5B,QAAsC;AAC7E,QAAM,EAAE6B,SAASC,UAAU,GAAGb,SAAAA,IAAajB;AAE3C,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNY,OAAO;QAAE5B,IAAI0B;QAASG,WAAWF,YAAY5C;MAAwB;MACrEmC,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBmC;AAiCT,SAASK,yBAAyBjC,QAAsC;AAC7E,QAAM,EAAEkC,WAAWL,SAASC,UAAUK,UAAUC,SAAS,GAAGnB,SAAAA,IAAajB;AAEzE,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAMe;MACN,CAACA,SAAAA,GAAY;QACX/B,IAAI0B;QACJ,GAAIC,WAAW;UAAEE,WAAWF;QAAS,IAAI,CAAC;QAC1C,GAAIK,WAAW;UAAEA;QAAS,IAAI,CAAC;QAC/B,GAAIC,UAAU;UAAEA;QAAQ,IAAI,CAAC;MAC/B;MACAf,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAlBgBwC;AAyBT,SAASI,wBAAwBC,SAA+B;AACrE,SAAOC,KAAKC,UAAUF,OAAAA;AACxB;AAFgBD;","names":["PREVIEW_PHONE_NUMBER_ID","PREVIEW_WABA_ID","PREVIEW_DISPLAY_PHONE_NUMBER","PREVIEW_AUDIO_MIME_TYPE","generateWamid","unique","globalThis","crypto","randomUUID","replaceAll","currentTimestamp","Math","floor","Date","now","toString","buildEnvelope","params","object","entry","id","wabaId","changes","value","messaging_product","metadata","display_phone_number","displayPhoneNumber","phone_number_id","phoneNumberId","messages","message","buildInboundTextPayload","text","envelope","from","type","body","timestamp","buildInboundInteractivePayload","buttonReply","listReply","interactive","button_reply","list_reply","buildInboundAudioPayload","mediaId","mimeType","audio","mime_type","buildInboundMediaPayload","mediaType","filename","caption","serializeWebhookPayload","payload","JSON","stringify"]}
1
+ {"version":3,"sources":["../../src/testing/index.ts","../../src/testing/inboundPayloads.ts"],"sourcesContent":["/**\n * Export separado (`@adatechnology/meta-whatsapp-contracts/testing`): utilitário de\n * desenvolvimento não entra no grafo de import de quem consome os contratos em produção.\n */\n\nexport {\n buildInboundTextPayload,\n buildInboundInteractivePayload,\n buildInboundAudioPayload,\n buildInboundMediaPayload,\n serializeWebhookPayload,\n PREVIEW_PHONE_NUMBER_ID,\n PREVIEW_WABA_ID,\n PREVIEW_DISPLAY_PHONE_NUMBER,\n PREVIEW_AUDIO_MIME_TYPE,\n} from './inboundPayloads'\n\nexport type {\n BuildInboundTextPayloadParams,\n BuildInboundInteractivePayloadParams,\n BuildInboundAudioPayloadParams,\n BuildInboundMediaPayloadParams,\n InboundMediaType,\n InteractiveReplyOption,\n} from './inboundPayloads'\n","/**\n * Builders de payload inbound para exercitar o webhook em desenvolvimento sem um app da Meta\n * credenciado. Moram aqui, e não no módulo, por uma razão de runtime: o preview do navegador\n * precisa montar payloads, e o módulo depende de `node:crypto` — importá-lo do frontend quebraria\n * o bundle. Este pacote só depende de zod, então roda nos dois lados.\n *\n * São construção de payload, não assinatura: assinar depende do runtime (`node:crypto` no\n * servidor, WebCrypto no navegador) e fica com quem tem o segredo.\n *\n * Por que `id` e `timestamp` são novos a cada chamada: o anti-replay do webhook usa o header de\n * assinatura como nonce, e a assinatura é derivada do corpo cru. Dois payloads idênticos geram a\n * mesma assinatura, e a segunda entrega é descartada como duplicata — numa conversa real (\"sim\"\n * duas vezes) isso apareceria como mensagem engolida, sem erro nenhum para investigar.\n */\n\nimport type { WhatsAppMessage, WhatsAppWebhookPayload } from '../webhook.types'\n\n// Valores de dev que espelham o formato dos reais (15 dígitos) sem apontar para nada da Meta.\nexport const PREVIEW_PHONE_NUMBER_ID = '000000000000000'\nexport const PREVIEW_WABA_ID = '000000000000001'\nexport const PREVIEW_DISPLAY_PHONE_NUMBER = '+5511900000000'\n\n// O que a Meta manda para áudio gravado no app; o pipeline de STT depende do mime para decodificar.\nexport const PREVIEW_AUDIO_MIME_TYPE = 'audio/ogg; codecs=opus'\n\ntype InboundEnvelopeParams = {\n readonly from: string\n readonly phoneNumberId?: string\n readonly displayPhoneNumber?: string\n readonly wabaId?: string\n /**\n * Nome de perfil de quem manda, como a Meta o entrega em `contacts`.\n *\n * Ausente = webhook sem `contacts`, que é payload legítimo e precisa continuar sendo testável:\n * um builder que sempre injetasse contato esconderia o caminho em que o nome não vem.\n */\n readonly profileName?: string\n}\n\n// `globalThis.crypto` em vez de `node:crypto`: é o que existe tanto no navegador quanto no Node\n// 19+/Bun, e é o que mantém estes builders utilizáveis pelo preview do navegador.\nfunction generateWamid(): string {\n // Formato real é `wamid.<base64>`. O prefixo importa para quem faz parsing por prefixo; o corpo\n // só precisa ser único por entrega, que é o que mantém a assinatura — e o nonce — distinta.\n const unique = globalThis.crypto.randomUUID().replaceAll('-', '')\n return `wamid.${unique}`\n}\n\nfunction currentTimestamp(): string {\n return Math.floor(Date.now() / 1000).toString()\n}\n\ntype BuildEnvelopeParams = InboundEnvelopeParams & {\n readonly message: WhatsAppMessage\n}\n\nfunction buildEnvelope(params: BuildEnvelopeParams): WhatsAppWebhookPayload {\n return {\n object: 'whatsapp_business_account',\n entry: [\n {\n id: params.wabaId ?? PREVIEW_WABA_ID,\n changes: [\n {\n value: {\n messaging_product: 'whatsapp',\n metadata: {\n display_phone_number: params.displayPhoneNumber ?? PREVIEW_DISPLAY_PHONE_NUMBER,\n phone_number_id: params.phoneNumberId ?? PREVIEW_PHONE_NUMBER_ID,\n },\n messages: [params.message],\n ...(params.profileName\n ? { contacts: [{ wa_id: params.from, profile: { name: params.profileName } }] }\n : {}),\n },\n },\n ],\n },\n ],\n }\n}\n\nexport type BuildInboundTextPayloadParams = InboundEnvelopeParams & {\n readonly text: string\n}\n\nexport function buildInboundTextPayload(params: BuildInboundTextPayloadParams): WhatsAppWebhookPayload {\n const { text, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'text',\n text: { body: text },\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type InteractiveReplyOption = {\n readonly id: string\n readonly title: string\n}\n\n// União exclusiva: uma resposta interativa é de botão OU de lista, nunca das duas nem de nenhuma.\n// O tipo torna o erro impossível em vez de validá-lo em runtime.\nexport type BuildInboundInteractivePayloadParams = InboundEnvelopeParams &\n (\n | { readonly buttonReply: InteractiveReplyOption; readonly listReply?: never }\n | { readonly listReply: InteractiveReplyOption; readonly buttonReply?: never }\n )\n\nexport function buildInboundInteractivePayload(params: BuildInboundInteractivePayloadParams): WhatsAppWebhookPayload {\n const { buttonReply, listReply, ...envelope } = params\n\n const interactive = buttonReply\n ? { type: 'button_reply', button_reply: buttonReply }\n : { type: 'list_reply', list_reply: listReply }\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'interactive',\n interactive,\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type BuildInboundAudioPayloadParams = InboundEnvelopeParams & {\n readonly mediaId: string\n readonly mimeType?: string\n}\n\nexport function buildInboundAudioPayload(params: BuildInboundAudioPayloadParams): WhatsAppWebhookPayload {\n const { mediaId, mimeType, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'audio',\n audio: { id: mediaId, mime_type: mimeType ?? PREVIEW_AUDIO_MIME_TYPE },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/** Tipos de mídia que a Meta entrega por `id`, para o consumidor baixar depois. */\nexport type InboundMediaType = 'image' | 'video' | 'audio' | 'document' | 'sticker'\n\nexport type BuildInboundMediaPayloadParams = InboundEnvelopeParams & {\n readonly mediaType: InboundMediaType\n readonly mediaId: string\n readonly mimeType?: string\n readonly filename?: string\n readonly caption?: string\n}\n\n/**\n * Mídia genérica. O bloco vai com o nome do próprio tipo (`image`, `document`, …) porque é assim que\n * a Meta monta o webhook — e é por esse nome que o consumidor localiza o `id` para baixar o arquivo.\n *\n * `filename` só existe em documento e `caption` só em imagem/vídeo/documento; enviar os dois em\n * áudio geraria um payload que a Meta nunca produz, então eles são omitidos quando vazios.\n */\nexport function buildInboundMediaPayload(params: BuildInboundMediaPayloadParams): WhatsAppWebhookPayload {\n const { mediaType, mediaId, mimeType, filename, caption, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: mediaType,\n [mediaType]: {\n id: mediaId,\n ...(mimeType ? { mime_type: mimeType } : {}),\n ...(filename ? { filename } : {}),\n ...(caption ? { caption } : {}),\n },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/**\n * Serializa o payload uma única vez. A validação assina os bytes exatos recebidos: quem reserializa\n * antes de enviar (ou deixa o cliente HTTP serializar o objeto) muda espaçamento/ordem e derruba a\n * assinatura. Assinar e enviar SEMPRE a string devolvida aqui é o contrato.\n */\nexport function serializeWebhookPayload(payload: WhatsAppWebhookPayload): string {\n return JSON.stringify(payload)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;ACkBO,IAAMA,0BAA0B;AAChC,IAAMC,kBAAkB;AACxB,IAAMC,+BAA+B;AAGrC,IAAMC,0BAA0B;AAkBvC,SAASC,gBAAAA;AAGP,QAAMC,SAASC,WAAWC,OAAOC,WAAU,EAAGC,WAAW,KAAK,EAAA;AAC9D,SAAO,SAASJ,MAAAA;AAClB;AALSD;AAOT,SAASM,mBAAAA;AACP,SAAOC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA,EAAMC,SAAQ;AAC/C;AAFSL;AAQT,SAASM,cAAcC,QAA2B;AAChD,SAAO;IACLC,QAAQ;IACRC,OAAO;MACL;QACEC,IAAIH,OAAOI,UAAUpB;QACrBqB,SAAS;UACP;YACEC,OAAO;cACLC,mBAAmB;cACnBC,UAAU;gBACRC,sBAAsBT,OAAOU,sBAAsBzB;gBACnD0B,iBAAiBX,OAAOY,iBAAiB7B;cAC3C;cACA8B,UAAU;gBAACb,OAAOc;;cAClB,GAAId,OAAOe,cACP;gBAAEC,UAAU;kBAAC;oBAAEC,OAAOjB,OAAOkB;oBAAMC,SAAS;sBAAEC,MAAMpB,OAAOe;oBAAY;kBAAE;;cAAG,IAC5E,CAAC;YACP;UACF;;MAEJ;;EAEJ;AACF;AAxBShB;AA8BF,SAASsB,wBAAwBrB,QAAqC;AAC3E,QAAM,EAAEsB,MAAM,GAAGC,SAAAA,IAAavB;AAE9B,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNF,MAAM;QAAEG,MAAMH;MAAK;MACnBI,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAbgB4B;AA4BT,SAASM,+BAA+B3B,QAA4C;AACzF,QAAM,EAAE4B,aAAaC,WAAW,GAAGN,SAAAA,IAAavB;AAEhD,QAAM8B,cAAcF,cAChB;IAAEJ,MAAM;IAAgBO,cAAcH;EAAY,IAClD;IAAEJ,MAAM;IAAcQ,YAAYH;EAAU;AAEhD,SAAO9B,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNM;MACAJ,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAjBgBkC;AAwBT,SAASM,yBAAyBjC,QAAsC;AAC7E,QAAM,EAAEkC,SAASC,UAAU,GAAGZ,SAAAA,IAAavB;AAE3C,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNY,OAAO;QAAEjC,IAAI+B;QAASG,WAAWF,YAAYjD;MAAwB;MACrEwC,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBwC;AAiCT,SAASK,yBAAyBtC,QAAsC;AAC7E,QAAM,EAAEuC,WAAWL,SAASC,UAAUK,UAAUC,SAAS,GAAGlB,SAAAA,IAAavB;AAEzE,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAMe;MACN,CAACA,SAAAA,GAAY;QACXpC,IAAI+B;QACJ,GAAIC,WAAW;UAAEE,WAAWF;QAAS,IAAI,CAAC;QAC1C,GAAIK,WAAW;UAAEA;QAAS,IAAI,CAAC;QAC/B,GAAIC,UAAU;UAAEA;QAAQ,IAAI,CAAC;MAC/B;MACAf,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAlBgB6C;AAyBT,SAASI,wBAAwBC,SAA+B;AACrE,SAAOC,KAAKC,UAAUF,OAAAA;AACxB;AAFgBD;","names":["PREVIEW_PHONE_NUMBER_ID","PREVIEW_WABA_ID","PREVIEW_DISPLAY_PHONE_NUMBER","PREVIEW_AUDIO_MIME_TYPE","generateWamid","unique","globalThis","crypto","randomUUID","replaceAll","currentTimestamp","Math","floor","Date","now","toString","buildEnvelope","params","object","entry","id","wabaId","changes","value","messaging_product","metadata","display_phone_number","displayPhoneNumber","phone_number_id","phoneNumberId","messages","message","profileName","contacts","wa_id","from","profile","name","buildInboundTextPayload","text","envelope","type","body","timestamp","buildInboundInteractivePayload","buttonReply","listReply","interactive","button_reply","list_reply","buildInboundAudioPayload","mediaId","mimeType","audio","mime_type","buildInboundMediaPayload","mediaType","filename","caption","serializeWebhookPayload","payload","JSON","stringify"]}
@@ -1,4 +1,4 @@
1
- import { n as WhatsAppWebhookPayload } from '../webhook.types-DWaAhvNu.cjs';
1
+ import { o as WhatsAppWebhookPayload } from '../webhook.types-DzSMUGwM.cjs';
2
2
  import 'zod';
3
3
 
4
4
  /**
@@ -25,6 +25,13 @@ type InboundEnvelopeParams = {
25
25
  readonly phoneNumberId?: string;
26
26
  readonly displayPhoneNumber?: string;
27
27
  readonly wabaId?: string;
28
+ /**
29
+ * Nome de perfil de quem manda, como a Meta o entrega em `contacts`.
30
+ *
31
+ * Ausente = webhook sem `contacts`, que é payload legítimo e precisa continuar sendo testável:
32
+ * um builder que sempre injetasse contato esconderia o caminho em que o nome não vem.
33
+ */
34
+ readonly profileName?: string;
28
35
  };
29
36
  type BuildInboundTextPayloadParams = InboundEnvelopeParams & {
30
37
  readonly text: string;
@@ -1,4 +1,4 @@
1
- import { n as WhatsAppWebhookPayload } from '../webhook.types-DWaAhvNu.js';
1
+ import { o as WhatsAppWebhookPayload } from '../webhook.types-DzSMUGwM.js';
2
2
  import 'zod';
3
3
 
4
4
  /**
@@ -25,6 +25,13 @@ type InboundEnvelopeParams = {
25
25
  readonly phoneNumberId?: string;
26
26
  readonly displayPhoneNumber?: string;
27
27
  readonly wabaId?: string;
28
+ /**
29
+ * Nome de perfil de quem manda, como a Meta o entrega em `contacts`.
30
+ *
31
+ * Ausente = webhook sem `contacts`, que é payload legítimo e precisa continuar sendo testável:
32
+ * um builder que sempre injetasse contato esconderia o caminho em que o nome não vem.
33
+ */
34
+ readonly profileName?: string;
28
35
  };
29
36
  type BuildInboundTextPayloadParams = InboundEnvelopeParams & {
30
37
  readonly text: string;
@@ -31,7 +31,17 @@ function buildEnvelope(params) {
31
31
  },
32
32
  messages: [
33
33
  params.message
34
- ]
34
+ ],
35
+ ...params.profileName ? {
36
+ contacts: [
37
+ {
38
+ wa_id: params.from,
39
+ profile: {
40
+ name: params.profileName
41
+ }
42
+ }
43
+ ]
44
+ } : {}
35
45
  }
36
46
  }
37
47
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/inboundPayloads.ts"],"sourcesContent":["/**\n * Builders de payload inbound para exercitar o webhook em desenvolvimento sem um app da Meta\n * credenciado. Moram aqui, e não no módulo, por uma razão de runtime: o preview do navegador\n * precisa montar payloads, e o módulo depende de `node:crypto` — importá-lo do frontend quebraria\n * o bundle. Este pacote só depende de zod, então roda nos dois lados.\n *\n * São construção de payload, não assinatura: assinar depende do runtime (`node:crypto` no\n * servidor, WebCrypto no navegador) e fica com quem tem o segredo.\n *\n * Por que `id` e `timestamp` são novos a cada chamada: o anti-replay do webhook usa o header de\n * assinatura como nonce, e a assinatura é derivada do corpo cru. Dois payloads idênticos geram a\n * mesma assinatura, e a segunda entrega é descartada como duplicata — numa conversa real (\"sim\"\n * duas vezes) isso apareceria como mensagem engolida, sem erro nenhum para investigar.\n */\n\nimport type { WhatsAppMessage, WhatsAppWebhookPayload } from '../webhook.types'\n\n// Valores de dev que espelham o formato dos reais (15 dígitos) sem apontar para nada da Meta.\nexport const PREVIEW_PHONE_NUMBER_ID = '000000000000000'\nexport const PREVIEW_WABA_ID = '000000000000001'\nexport const PREVIEW_DISPLAY_PHONE_NUMBER = '+5511900000000'\n\n// O que a Meta manda para áudio gravado no app; o pipeline de STT depende do mime para decodificar.\nexport const PREVIEW_AUDIO_MIME_TYPE = 'audio/ogg; codecs=opus'\n\ntype InboundEnvelopeParams = {\n readonly from: string\n readonly phoneNumberId?: string\n readonly displayPhoneNumber?: string\n readonly wabaId?: string\n}\n\n// `globalThis.crypto` em vez de `node:crypto`: é o que existe tanto no navegador quanto no Node\n// 19+/Bun, e é o que mantém estes builders utilizáveis pelo preview do navegador.\nfunction generateWamid(): string {\n // Formato real é `wamid.<base64>`. O prefixo importa para quem faz parsing por prefixo; o corpo\n // só precisa ser único por entrega, que é o que mantém a assinatura — e o nonce — distinta.\n const unique = globalThis.crypto.randomUUID().replaceAll('-', '')\n return `wamid.${unique}`\n}\n\nfunction currentTimestamp(): string {\n return Math.floor(Date.now() / 1000).toString()\n}\n\ntype BuildEnvelopeParams = InboundEnvelopeParams & {\n readonly message: WhatsAppMessage\n}\n\nfunction buildEnvelope(params: BuildEnvelopeParams): WhatsAppWebhookPayload {\n return {\n object: 'whatsapp_business_account',\n entry: [\n {\n id: params.wabaId ?? PREVIEW_WABA_ID,\n changes: [\n {\n value: {\n messaging_product: 'whatsapp',\n metadata: {\n display_phone_number: params.displayPhoneNumber ?? PREVIEW_DISPLAY_PHONE_NUMBER,\n phone_number_id: params.phoneNumberId ?? PREVIEW_PHONE_NUMBER_ID,\n },\n messages: [params.message],\n },\n },\n ],\n },\n ],\n }\n}\n\nexport type BuildInboundTextPayloadParams = InboundEnvelopeParams & {\n readonly text: string\n}\n\nexport function buildInboundTextPayload(params: BuildInboundTextPayloadParams): WhatsAppWebhookPayload {\n const { text, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'text',\n text: { body: text },\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type InteractiveReplyOption = {\n readonly id: string\n readonly title: string\n}\n\n// União exclusiva: uma resposta interativa é de botão OU de lista, nunca das duas nem de nenhuma.\n// O tipo torna o erro impossível em vez de validá-lo em runtime.\nexport type BuildInboundInteractivePayloadParams = InboundEnvelopeParams &\n (\n | { readonly buttonReply: InteractiveReplyOption; readonly listReply?: never }\n | { readonly listReply: InteractiveReplyOption; readonly buttonReply?: never }\n )\n\nexport function buildInboundInteractivePayload(params: BuildInboundInteractivePayloadParams): WhatsAppWebhookPayload {\n const { buttonReply, listReply, ...envelope } = params\n\n const interactive = buttonReply\n ? { type: 'button_reply', button_reply: buttonReply }\n : { type: 'list_reply', list_reply: listReply }\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'interactive',\n interactive,\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type BuildInboundAudioPayloadParams = InboundEnvelopeParams & {\n readonly mediaId: string\n readonly mimeType?: string\n}\n\nexport function buildInboundAudioPayload(params: BuildInboundAudioPayloadParams): WhatsAppWebhookPayload {\n const { mediaId, mimeType, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'audio',\n audio: { id: mediaId, mime_type: mimeType ?? PREVIEW_AUDIO_MIME_TYPE },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/** Tipos de mídia que a Meta entrega por `id`, para o consumidor baixar depois. */\nexport type InboundMediaType = 'image' | 'video' | 'audio' | 'document' | 'sticker'\n\nexport type BuildInboundMediaPayloadParams = InboundEnvelopeParams & {\n readonly mediaType: InboundMediaType\n readonly mediaId: string\n readonly mimeType?: string\n readonly filename?: string\n readonly caption?: string\n}\n\n/**\n * Mídia genérica. O bloco vai com o nome do próprio tipo (`image`, `document`, …) porque é assim que\n * a Meta monta o webhook — e é por esse nome que o consumidor localiza o `id` para baixar o arquivo.\n *\n * `filename` só existe em documento e `caption` só em imagem/vídeo/documento; enviar os dois em\n * áudio geraria um payload que a Meta nunca produz, então eles são omitidos quando vazios.\n */\nexport function buildInboundMediaPayload(params: BuildInboundMediaPayloadParams): WhatsAppWebhookPayload {\n const { mediaType, mediaId, mimeType, filename, caption, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: mediaType,\n [mediaType]: {\n id: mediaId,\n ...(mimeType ? { mime_type: mimeType } : {}),\n ...(filename ? { filename } : {}),\n ...(caption ? { caption } : {}),\n },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/**\n * Serializa o payload uma única vez. A validação assina os bytes exatos recebidos: quem reserializa\n * antes de enviar (ou deixa o cliente HTTP serializar o objeto) muda espaçamento/ordem e derruba a\n * assinatura. Assinar e enviar SEMPRE a string devolvida aqui é o contrato.\n */\nexport function serializeWebhookPayload(payload: WhatsAppWebhookPayload): string {\n return JSON.stringify(payload)\n}\n"],"mappings":";;;;AAkBO,IAAMA,0BAA0B;AAChC,IAAMC,kBAAkB;AACxB,IAAMC,+BAA+B;AAGrC,IAAMC,0BAA0B;AAWvC,SAASC,gBAAAA;AAGP,QAAMC,SAASC,WAAWC,OAAOC,WAAU,EAAGC,WAAW,KAAK,EAAA;AAC9D,SAAO,SAASJ,MAAAA;AAClB;AALSD;AAOT,SAASM,mBAAAA;AACP,SAAOC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA,EAAMC,SAAQ;AAC/C;AAFSL;AAQT,SAASM,cAAcC,QAA2B;AAChD,SAAO;IACLC,QAAQ;IACRC,OAAO;MACL;QACEC,IAAIH,OAAOI,UAAUpB;QACrBqB,SAAS;UACP;YACEC,OAAO;cACLC,mBAAmB;cACnBC,UAAU;gBACRC,sBAAsBT,OAAOU,sBAAsBzB;gBACnD0B,iBAAiBX,OAAOY,iBAAiB7B;cAC3C;cACA8B,UAAU;gBAACb,OAAOc;;YACpB;UACF;;MAEJ;;EAEJ;AACF;AArBSf;AA2BF,SAASgB,wBAAwBf,QAAqC;AAC3E,QAAM,EAAEgB,MAAM,GAAGC,SAAAA,IAAajB;AAE9B,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNH,MAAM;QAAEI,MAAMJ;MAAK;MACnBK,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBsB;AA4BT,SAASO,+BAA+BtB,QAA4C;AACzF,QAAM,EAAEuB,aAAaC,WAAW,GAAGP,SAAAA,IAAajB;AAEhD,QAAMyB,cAAcF,cAChB;IAAEJ,MAAM;IAAgBO,cAAcH;EAAY,IAClD;IAAEJ,MAAM;IAAcQ,YAAYH;EAAU;AAEhD,SAAOzB,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNM;MACAJ,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAjBgB6B;AAwBT,SAASM,yBAAyB5B,QAAsC;AAC7E,QAAM,EAAE6B,SAASC,UAAU,GAAGb,SAAAA,IAAajB;AAE3C,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAM;MACNY,OAAO;QAAE5B,IAAI0B;QAASG,WAAWF,YAAY5C;MAAwB;MACrEmC,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBmC;AAiCT,SAASK,yBAAyBjC,QAAsC;AAC7E,QAAM,EAAEkC,WAAWL,SAASC,UAAUK,UAAUC,SAAS,GAAGnB,SAAAA,IAAajB;AAEzE,SAAOD,cAAc;IACnB,GAAGkB;IACHH,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbC,MAAMe;MACN,CAACA,SAAAA,GAAY;QACX/B,IAAI0B;QACJ,GAAIC,WAAW;UAAEE,WAAWF;QAAS,IAAI,CAAC;QAC1C,GAAIK,WAAW;UAAEA;QAAS,IAAI,CAAC;QAC/B,GAAIC,UAAU;UAAEA;QAAQ,IAAI,CAAC;MAC/B;MACAf,WAAW5B,iBAAAA;IACb;EACF,CAAA;AACF;AAlBgBwC;AAyBT,SAASI,wBAAwBC,SAA+B;AACrE,SAAOC,KAAKC,UAAUF,OAAAA;AACxB;AAFgBD;","names":["PREVIEW_PHONE_NUMBER_ID","PREVIEW_WABA_ID","PREVIEW_DISPLAY_PHONE_NUMBER","PREVIEW_AUDIO_MIME_TYPE","generateWamid","unique","globalThis","crypto","randomUUID","replaceAll","currentTimestamp","Math","floor","Date","now","toString","buildEnvelope","params","object","entry","id","wabaId","changes","value","messaging_product","metadata","display_phone_number","displayPhoneNumber","phone_number_id","phoneNumberId","messages","message","buildInboundTextPayload","text","envelope","from","type","body","timestamp","buildInboundInteractivePayload","buttonReply","listReply","interactive","button_reply","list_reply","buildInboundAudioPayload","mediaId","mimeType","audio","mime_type","buildInboundMediaPayload","mediaType","filename","caption","serializeWebhookPayload","payload","JSON","stringify"]}
1
+ {"version":3,"sources":["../../src/testing/inboundPayloads.ts"],"sourcesContent":["/**\n * Builders de payload inbound para exercitar o webhook em desenvolvimento sem um app da Meta\n * credenciado. Moram aqui, e não no módulo, por uma razão de runtime: o preview do navegador\n * precisa montar payloads, e o módulo depende de `node:crypto` — importá-lo do frontend quebraria\n * o bundle. Este pacote só depende de zod, então roda nos dois lados.\n *\n * São construção de payload, não assinatura: assinar depende do runtime (`node:crypto` no\n * servidor, WebCrypto no navegador) e fica com quem tem o segredo.\n *\n * Por que `id` e `timestamp` são novos a cada chamada: o anti-replay do webhook usa o header de\n * assinatura como nonce, e a assinatura é derivada do corpo cru. Dois payloads idênticos geram a\n * mesma assinatura, e a segunda entrega é descartada como duplicata — numa conversa real (\"sim\"\n * duas vezes) isso apareceria como mensagem engolida, sem erro nenhum para investigar.\n */\n\nimport type { WhatsAppMessage, WhatsAppWebhookPayload } from '../webhook.types'\n\n// Valores de dev que espelham o formato dos reais (15 dígitos) sem apontar para nada da Meta.\nexport const PREVIEW_PHONE_NUMBER_ID = '000000000000000'\nexport const PREVIEW_WABA_ID = '000000000000001'\nexport const PREVIEW_DISPLAY_PHONE_NUMBER = '+5511900000000'\n\n// O que a Meta manda para áudio gravado no app; o pipeline de STT depende do mime para decodificar.\nexport const PREVIEW_AUDIO_MIME_TYPE = 'audio/ogg; codecs=opus'\n\ntype InboundEnvelopeParams = {\n readonly from: string\n readonly phoneNumberId?: string\n readonly displayPhoneNumber?: string\n readonly wabaId?: string\n /**\n * Nome de perfil de quem manda, como a Meta o entrega em `contacts`.\n *\n * Ausente = webhook sem `contacts`, que é payload legítimo e precisa continuar sendo testável:\n * um builder que sempre injetasse contato esconderia o caminho em que o nome não vem.\n */\n readonly profileName?: string\n}\n\n// `globalThis.crypto` em vez de `node:crypto`: é o que existe tanto no navegador quanto no Node\n// 19+/Bun, e é o que mantém estes builders utilizáveis pelo preview do navegador.\nfunction generateWamid(): string {\n // Formato real é `wamid.<base64>`. O prefixo importa para quem faz parsing por prefixo; o corpo\n // só precisa ser único por entrega, que é o que mantém a assinatura — e o nonce — distinta.\n const unique = globalThis.crypto.randomUUID().replaceAll('-', '')\n return `wamid.${unique}`\n}\n\nfunction currentTimestamp(): string {\n return Math.floor(Date.now() / 1000).toString()\n}\n\ntype BuildEnvelopeParams = InboundEnvelopeParams & {\n readonly message: WhatsAppMessage\n}\n\nfunction buildEnvelope(params: BuildEnvelopeParams): WhatsAppWebhookPayload {\n return {\n object: 'whatsapp_business_account',\n entry: [\n {\n id: params.wabaId ?? PREVIEW_WABA_ID,\n changes: [\n {\n value: {\n messaging_product: 'whatsapp',\n metadata: {\n display_phone_number: params.displayPhoneNumber ?? PREVIEW_DISPLAY_PHONE_NUMBER,\n phone_number_id: params.phoneNumberId ?? PREVIEW_PHONE_NUMBER_ID,\n },\n messages: [params.message],\n ...(params.profileName\n ? { contacts: [{ wa_id: params.from, profile: { name: params.profileName } }] }\n : {}),\n },\n },\n ],\n },\n ],\n }\n}\n\nexport type BuildInboundTextPayloadParams = InboundEnvelopeParams & {\n readonly text: string\n}\n\nexport function buildInboundTextPayload(params: BuildInboundTextPayloadParams): WhatsAppWebhookPayload {\n const { text, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'text',\n text: { body: text },\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type InteractiveReplyOption = {\n readonly id: string\n readonly title: string\n}\n\n// União exclusiva: uma resposta interativa é de botão OU de lista, nunca das duas nem de nenhuma.\n// O tipo torna o erro impossível em vez de validá-lo em runtime.\nexport type BuildInboundInteractivePayloadParams = InboundEnvelopeParams &\n (\n | { readonly buttonReply: InteractiveReplyOption; readonly listReply?: never }\n | { readonly listReply: InteractiveReplyOption; readonly buttonReply?: never }\n )\n\nexport function buildInboundInteractivePayload(params: BuildInboundInteractivePayloadParams): WhatsAppWebhookPayload {\n const { buttonReply, listReply, ...envelope } = params\n\n const interactive = buttonReply\n ? { type: 'button_reply', button_reply: buttonReply }\n : { type: 'list_reply', list_reply: listReply }\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'interactive',\n interactive,\n timestamp: currentTimestamp(),\n },\n })\n}\n\nexport type BuildInboundAudioPayloadParams = InboundEnvelopeParams & {\n readonly mediaId: string\n readonly mimeType?: string\n}\n\nexport function buildInboundAudioPayload(params: BuildInboundAudioPayloadParams): WhatsAppWebhookPayload {\n const { mediaId, mimeType, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: 'audio',\n audio: { id: mediaId, mime_type: mimeType ?? PREVIEW_AUDIO_MIME_TYPE },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/** Tipos de mídia que a Meta entrega por `id`, para o consumidor baixar depois. */\nexport type InboundMediaType = 'image' | 'video' | 'audio' | 'document' | 'sticker'\n\nexport type BuildInboundMediaPayloadParams = InboundEnvelopeParams & {\n readonly mediaType: InboundMediaType\n readonly mediaId: string\n readonly mimeType?: string\n readonly filename?: string\n readonly caption?: string\n}\n\n/**\n * Mídia genérica. O bloco vai com o nome do próprio tipo (`image`, `document`, …) porque é assim que\n * a Meta monta o webhook — e é por esse nome que o consumidor localiza o `id` para baixar o arquivo.\n *\n * `filename` só existe em documento e `caption` só em imagem/vídeo/documento; enviar os dois em\n * áudio geraria um payload que a Meta nunca produz, então eles são omitidos quando vazios.\n */\nexport function buildInboundMediaPayload(params: BuildInboundMediaPayloadParams): WhatsAppWebhookPayload {\n const { mediaType, mediaId, mimeType, filename, caption, ...envelope } = params\n\n return buildEnvelope({\n ...envelope,\n message: {\n id: generateWamid(),\n from: params.from,\n type: mediaType,\n [mediaType]: {\n id: mediaId,\n ...(mimeType ? { mime_type: mimeType } : {}),\n ...(filename ? { filename } : {}),\n ...(caption ? { caption } : {}),\n },\n timestamp: currentTimestamp(),\n },\n })\n}\n\n/**\n * Serializa o payload uma única vez. A validação assina os bytes exatos recebidos: quem reserializa\n * antes de enviar (ou deixa o cliente HTTP serializar o objeto) muda espaçamento/ordem e derruba a\n * assinatura. Assinar e enviar SEMPRE a string devolvida aqui é o contrato.\n */\nexport function serializeWebhookPayload(payload: WhatsAppWebhookPayload): string {\n return JSON.stringify(payload)\n}\n"],"mappings":";;;;AAkBO,IAAMA,0BAA0B;AAChC,IAAMC,kBAAkB;AACxB,IAAMC,+BAA+B;AAGrC,IAAMC,0BAA0B;AAkBvC,SAASC,gBAAAA;AAGP,QAAMC,SAASC,WAAWC,OAAOC,WAAU,EAAGC,WAAW,KAAK,EAAA;AAC9D,SAAO,SAASJ,MAAAA;AAClB;AALSD;AAOT,SAASM,mBAAAA;AACP,SAAOC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA,EAAMC,SAAQ;AAC/C;AAFSL;AAQT,SAASM,cAAcC,QAA2B;AAChD,SAAO;IACLC,QAAQ;IACRC,OAAO;MACL;QACEC,IAAIH,OAAOI,UAAUpB;QACrBqB,SAAS;UACP;YACEC,OAAO;cACLC,mBAAmB;cACnBC,UAAU;gBACRC,sBAAsBT,OAAOU,sBAAsBzB;gBACnD0B,iBAAiBX,OAAOY,iBAAiB7B;cAC3C;cACA8B,UAAU;gBAACb,OAAOc;;cAClB,GAAId,OAAOe,cACP;gBAAEC,UAAU;kBAAC;oBAAEC,OAAOjB,OAAOkB;oBAAMC,SAAS;sBAAEC,MAAMpB,OAAOe;oBAAY;kBAAE;;cAAG,IAC5E,CAAC;YACP;UACF;;MAEJ;;EAEJ;AACF;AAxBShB;AA8BF,SAASsB,wBAAwBrB,QAAqC;AAC3E,QAAM,EAAEsB,MAAM,GAAGC,SAAAA,IAAavB;AAE9B,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNF,MAAM;QAAEG,MAAMH;MAAK;MACnBI,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAbgB4B;AA4BT,SAASM,+BAA+B3B,QAA4C;AACzF,QAAM,EAAE4B,aAAaC,WAAW,GAAGN,SAAAA,IAAavB;AAEhD,QAAM8B,cAAcF,cAChB;IAAEJ,MAAM;IAAgBO,cAAcH;EAAY,IAClD;IAAEJ,MAAM;IAAcQ,YAAYH;EAAU;AAEhD,SAAO9B,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNM;MACAJ,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAjBgBkC;AAwBT,SAASM,yBAAyBjC,QAAsC;AAC7E,QAAM,EAAEkC,SAASC,UAAU,GAAGZ,SAAAA,IAAavB;AAE3C,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAM;MACNY,OAAO;QAAEjC,IAAI+B;QAASG,WAAWF,YAAYjD;MAAwB;MACrEwC,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAbgBwC;AAiCT,SAASK,yBAAyBtC,QAAsC;AAC7E,QAAM,EAAEuC,WAAWL,SAASC,UAAUK,UAAUC,SAAS,GAAGlB,SAAAA,IAAavB;AAEzE,SAAOD,cAAc;IACnB,GAAGwB;IACHT,SAAS;MACPX,IAAIhB,cAAAA;MACJ+B,MAAMlB,OAAOkB;MACbM,MAAMe;MACN,CAACA,SAAAA,GAAY;QACXpC,IAAI+B;QACJ,GAAIC,WAAW;UAAEE,WAAWF;QAAS,IAAI,CAAC;QAC1C,GAAIK,WAAW;UAAEA;QAAS,IAAI,CAAC;QAC/B,GAAIC,UAAU;UAAEA;QAAQ,IAAI,CAAC;MAC/B;MACAf,WAAWjC,iBAAAA;IACb;EACF,CAAA;AACF;AAlBgB6C;AAyBT,SAASI,wBAAwBC,SAA+B;AACrE,SAAOC,KAAKC,UAAUF,OAAAA;AACxB;AAFgBD;","names":["PREVIEW_PHONE_NUMBER_ID","PREVIEW_WABA_ID","PREVIEW_DISPLAY_PHONE_NUMBER","PREVIEW_AUDIO_MIME_TYPE","generateWamid","unique","globalThis","crypto","randomUUID","replaceAll","currentTimestamp","Math","floor","Date","now","toString","buildEnvelope","params","object","entry","id","wabaId","changes","value","messaging_product","metadata","display_phone_number","displayPhoneNumber","phone_number_id","phoneNumberId","messages","message","profileName","contacts","wa_id","from","profile","name","buildInboundTextPayload","text","envelope","type","body","timestamp","buildInboundInteractivePayload","buttonReply","listReply","interactive","button_reply","list_reply","buildInboundAudioPayload","mediaId","mimeType","audio","mime_type","buildInboundMediaPayload","mediaType","filename","caption","serializeWebhookPayload","payload","JSON","stringify"]}
@@ -552,6 +552,34 @@ declare const whatsAppPhoneNumberQualityUpdateSchema: z.ZodObject<{
552
552
  old_limit?: string | undefined;
553
553
  }>;
554
554
  type WhatsAppPhoneNumberQualityUpdate = z.infer<typeof whatsAppPhoneNumberQualityUpdateSchema>;
555
+ /**
556
+ * O contato que a Meta manda junto das mensagens. `profile.name` é o nome que a PESSOA escolheu no
557
+ * WhatsApp dela — é o único nome que existe antes de alguém digitar um, e sem ele o cliente criado
558
+ * por mensagem nasce sem nome nenhum.
559
+ *
560
+ * `profile` é opcional: a pessoa pode não ter nome definido, e a Meta omite o objeto nesse caso.
561
+ */
562
+ declare const whatsAppContactSchema: z.ZodObject<{
563
+ wa_id: z.ZodString;
564
+ profile: z.ZodOptional<z.ZodObject<{
565
+ name: z.ZodString;
566
+ }, "strip", z.ZodTypeAny, {
567
+ name: string;
568
+ }, {
569
+ name: string;
570
+ }>>;
571
+ }, "strip", z.ZodTypeAny, {
572
+ wa_id: string;
573
+ profile?: {
574
+ name: string;
575
+ } | undefined;
576
+ }, {
577
+ wa_id: string;
578
+ profile?: {
579
+ name: string;
580
+ } | undefined;
581
+ }>;
582
+ type WhatsAppContact = z.infer<typeof whatsAppContactSchema>;
555
583
  declare const whatsAppWebhookValueSchema: z.ZodObject<{
556
584
  messaging_product: z.ZodOptional<z.ZodString>;
557
585
  messages: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -915,6 +943,26 @@ declare const whatsAppWebhookValueSchema: z.ZodObject<{
915
943
  } | undefined;
916
944
  } | undefined;
917
945
  }>, "many">>;
946
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
947
+ wa_id: z.ZodString;
948
+ profile: z.ZodOptional<z.ZodObject<{
949
+ name: z.ZodString;
950
+ }, "strip", z.ZodTypeAny, {
951
+ name: string;
952
+ }, {
953
+ name: string;
954
+ }>>;
955
+ }, "strip", z.ZodTypeAny, {
956
+ wa_id: string;
957
+ profile?: {
958
+ name: string;
959
+ } | undefined;
960
+ }, {
961
+ wa_id: string;
962
+ profile?: {
963
+ name: string;
964
+ } | undefined;
965
+ }>, "many">>;
918
966
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
919
967
  id: z.ZodString;
920
968
  from: z.ZodString;
@@ -1320,6 +1368,26 @@ declare const whatsAppWebhookValueSchema: z.ZodObject<{
1320
1368
  } | undefined;
1321
1369
  } | undefined;
1322
1370
  }>, "many">>;
1371
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
1372
+ wa_id: z.ZodString;
1373
+ profile: z.ZodOptional<z.ZodObject<{
1374
+ name: z.ZodString;
1375
+ }, "strip", z.ZodTypeAny, {
1376
+ name: string;
1377
+ }, {
1378
+ name: string;
1379
+ }>>;
1380
+ }, "strip", z.ZodTypeAny, {
1381
+ wa_id: string;
1382
+ profile?: {
1383
+ name: string;
1384
+ } | undefined;
1385
+ }, {
1386
+ wa_id: string;
1387
+ profile?: {
1388
+ name: string;
1389
+ } | undefined;
1390
+ }>, "many">>;
1323
1391
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
1324
1392
  id: z.ZodString;
1325
1393
  from: z.ZodString;
@@ -1725,6 +1793,26 @@ declare const whatsAppWebhookValueSchema: z.ZodObject<{
1725
1793
  } | undefined;
1726
1794
  } | undefined;
1727
1795
  }>, "many">>;
1796
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
1797
+ wa_id: z.ZodString;
1798
+ profile: z.ZodOptional<z.ZodObject<{
1799
+ name: z.ZodString;
1800
+ }, "strip", z.ZodTypeAny, {
1801
+ name: string;
1802
+ }, {
1803
+ name: string;
1804
+ }>>;
1805
+ }, "strip", z.ZodTypeAny, {
1806
+ wa_id: string;
1807
+ profile?: {
1808
+ name: string;
1809
+ } | undefined;
1810
+ }, {
1811
+ wa_id: string;
1812
+ profile?: {
1813
+ name: string;
1814
+ } | undefined;
1815
+ }>, "many">>;
1728
1816
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
1729
1817
  id: z.ZodString;
1730
1818
  from: z.ZodString;
@@ -2134,6 +2222,26 @@ declare const whatsAppWebhookChangeSchema: z.ZodObject<{
2134
2222
  } | undefined;
2135
2223
  } | undefined;
2136
2224
  }>, "many">>;
2225
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
2226
+ wa_id: z.ZodString;
2227
+ profile: z.ZodOptional<z.ZodObject<{
2228
+ name: z.ZodString;
2229
+ }, "strip", z.ZodTypeAny, {
2230
+ name: string;
2231
+ }, {
2232
+ name: string;
2233
+ }>>;
2234
+ }, "strip", z.ZodTypeAny, {
2235
+ wa_id: string;
2236
+ profile?: {
2237
+ name: string;
2238
+ } | undefined;
2239
+ }, {
2240
+ wa_id: string;
2241
+ profile?: {
2242
+ name: string;
2243
+ } | undefined;
2244
+ }>, "many">>;
2137
2245
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
2138
2246
  id: z.ZodString;
2139
2247
  from: z.ZodString;
@@ -2539,6 +2647,26 @@ declare const whatsAppWebhookChangeSchema: z.ZodObject<{
2539
2647
  } | undefined;
2540
2648
  } | undefined;
2541
2649
  }>, "many">>;
2650
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
2651
+ wa_id: z.ZodString;
2652
+ profile: z.ZodOptional<z.ZodObject<{
2653
+ name: z.ZodString;
2654
+ }, "strip", z.ZodTypeAny, {
2655
+ name: string;
2656
+ }, {
2657
+ name: string;
2658
+ }>>;
2659
+ }, "strip", z.ZodTypeAny, {
2660
+ wa_id: string;
2661
+ profile?: {
2662
+ name: string;
2663
+ } | undefined;
2664
+ }, {
2665
+ wa_id: string;
2666
+ profile?: {
2667
+ name: string;
2668
+ } | undefined;
2669
+ }>, "many">>;
2542
2670
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
2543
2671
  id: z.ZodString;
2544
2672
  from: z.ZodString;
@@ -2944,6 +3072,26 @@ declare const whatsAppWebhookChangeSchema: z.ZodObject<{
2944
3072
  } | undefined;
2945
3073
  } | undefined;
2946
3074
  }>, "many">>;
3075
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
3076
+ wa_id: z.ZodString;
3077
+ profile: z.ZodOptional<z.ZodObject<{
3078
+ name: z.ZodString;
3079
+ }, "strip", z.ZodTypeAny, {
3080
+ name: string;
3081
+ }, {
3082
+ name: string;
3083
+ }>>;
3084
+ }, "strip", z.ZodTypeAny, {
3085
+ wa_id: string;
3086
+ profile?: {
3087
+ name: string;
3088
+ } | undefined;
3089
+ }, {
3090
+ wa_id: string;
3091
+ profile?: {
3092
+ name: string;
3093
+ } | undefined;
3094
+ }>, "many">>;
2947
3095
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
2948
3096
  id: z.ZodString;
2949
3097
  from: z.ZodString;
@@ -3069,6 +3217,12 @@ declare const whatsAppWebhookChangeSchema: z.ZodObject<{
3069
3217
  timestamp: string;
3070
3218
  }[] | undefined;
3071
3219
  messaging_product?: string | undefined;
3220
+ contacts?: {
3221
+ wa_id: string;
3222
+ profile?: {
3223
+ name: string;
3224
+ } | undefined;
3225
+ }[] | undefined;
3072
3226
  statuses?: {
3073
3227
  id: string;
3074
3228
  status: "sent" | "delivered" | "read" | "failed";
@@ -3165,6 +3319,12 @@ declare const whatsAppWebhookChangeSchema: z.ZodObject<{
3165
3319
  timestamp: string;
3166
3320
  }[] | undefined;
3167
3321
  messaging_product?: string | undefined;
3322
+ contacts?: {
3323
+ wa_id: string;
3324
+ profile?: {
3325
+ name: string;
3326
+ } | undefined;
3327
+ }[] | undefined;
3168
3328
  statuses?: {
3169
3329
  id: string;
3170
3330
  status: "sent" | "delivered" | "read" | "failed";
@@ -3550,6 +3710,26 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
3550
3710
  } | undefined;
3551
3711
  } | undefined;
3552
3712
  }>, "many">>;
3713
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
3714
+ wa_id: z.ZodString;
3715
+ profile: z.ZodOptional<z.ZodObject<{
3716
+ name: z.ZodString;
3717
+ }, "strip", z.ZodTypeAny, {
3718
+ name: string;
3719
+ }, {
3720
+ name: string;
3721
+ }>>;
3722
+ }, "strip", z.ZodTypeAny, {
3723
+ wa_id: string;
3724
+ profile?: {
3725
+ name: string;
3726
+ } | undefined;
3727
+ }, {
3728
+ wa_id: string;
3729
+ profile?: {
3730
+ name: string;
3731
+ } | undefined;
3732
+ }>, "many">>;
3553
3733
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
3554
3734
  id: z.ZodString;
3555
3735
  from: z.ZodString;
@@ -3955,6 +4135,26 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
3955
4135
  } | undefined;
3956
4136
  } | undefined;
3957
4137
  }>, "many">>;
4138
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
4139
+ wa_id: z.ZodString;
4140
+ profile: z.ZodOptional<z.ZodObject<{
4141
+ name: z.ZodString;
4142
+ }, "strip", z.ZodTypeAny, {
4143
+ name: string;
4144
+ }, {
4145
+ name: string;
4146
+ }>>;
4147
+ }, "strip", z.ZodTypeAny, {
4148
+ wa_id: string;
4149
+ profile?: {
4150
+ name: string;
4151
+ } | undefined;
4152
+ }, {
4153
+ wa_id: string;
4154
+ profile?: {
4155
+ name: string;
4156
+ } | undefined;
4157
+ }>, "many">>;
3958
4158
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
3959
4159
  id: z.ZodString;
3960
4160
  from: z.ZodString;
@@ -4360,6 +4560,26 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4360
4560
  } | undefined;
4361
4561
  } | undefined;
4362
4562
  }>, "many">>;
4563
+ contacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
4564
+ wa_id: z.ZodString;
4565
+ profile: z.ZodOptional<z.ZodObject<{
4566
+ name: z.ZodString;
4567
+ }, "strip", z.ZodTypeAny, {
4568
+ name: string;
4569
+ }, {
4570
+ name: string;
4571
+ }>>;
4572
+ }, "strip", z.ZodTypeAny, {
4573
+ wa_id: string;
4574
+ profile?: {
4575
+ name: string;
4576
+ } | undefined;
4577
+ }, {
4578
+ wa_id: string;
4579
+ profile?: {
4580
+ name: string;
4581
+ } | undefined;
4582
+ }>, "many">>;
4363
4583
  message_echoes: z.ZodOptional<z.ZodArray<z.ZodObject<{
4364
4584
  id: z.ZodString;
4365
4585
  from: z.ZodString;
@@ -4485,6 +4705,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4485
4705
  timestamp: string;
4486
4706
  }[] | undefined;
4487
4707
  messaging_product?: string | undefined;
4708
+ contacts?: {
4709
+ wa_id: string;
4710
+ profile?: {
4711
+ name: string;
4712
+ } | undefined;
4713
+ }[] | undefined;
4488
4714
  statuses?: {
4489
4715
  id: string;
4490
4716
  status: "sent" | "delivered" | "read" | "failed";
@@ -4581,6 +4807,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4581
4807
  timestamp: string;
4582
4808
  }[] | undefined;
4583
4809
  messaging_product?: string | undefined;
4810
+ contacts?: {
4811
+ wa_id: string;
4812
+ profile?: {
4813
+ name: string;
4814
+ } | undefined;
4815
+ }[] | undefined;
4584
4816
  statuses?: {
4585
4817
  id: string;
4586
4818
  status: "sent" | "delivered" | "read" | "failed";
@@ -4680,6 +4912,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4680
4912
  timestamp: string;
4681
4913
  }[] | undefined;
4682
4914
  messaging_product?: string | undefined;
4915
+ contacts?: {
4916
+ wa_id: string;
4917
+ profile?: {
4918
+ name: string;
4919
+ } | undefined;
4920
+ }[] | undefined;
4683
4921
  statuses?: {
4684
4922
  id: string;
4685
4923
  status: "sent" | "delivered" | "read" | "failed";
@@ -4779,6 +5017,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4779
5017
  timestamp: string;
4780
5018
  }[] | undefined;
4781
5019
  messaging_product?: string | undefined;
5020
+ contacts?: {
5021
+ wa_id: string;
5022
+ profile?: {
5023
+ name: string;
5024
+ } | undefined;
5025
+ }[] | undefined;
4782
5026
  statuses?: {
4783
5027
  id: string;
4784
5028
  status: "sent" | "delivered" | "read" | "failed";
@@ -4881,6 +5125,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4881
5125
  timestamp: string;
4882
5126
  }[] | undefined;
4883
5127
  messaging_product?: string | undefined;
5128
+ contacts?: {
5129
+ wa_id: string;
5130
+ profile?: {
5131
+ name: string;
5132
+ } | undefined;
5133
+ }[] | undefined;
4884
5134
  statuses?: {
4885
5135
  id: string;
4886
5136
  status: "sent" | "delivered" | "read" | "failed";
@@ -4983,6 +5233,12 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
4983
5233
  timestamp: string;
4984
5234
  }[] | undefined;
4985
5235
  messaging_product?: string | undefined;
5236
+ contacts?: {
5237
+ wa_id: string;
5238
+ profile?: {
5239
+ name: string;
5240
+ } | undefined;
5241
+ }[] | undefined;
4986
5242
  statuses?: {
4987
5243
  id: string;
4988
5244
  status: "sent" | "delivered" | "read" | "failed";
@@ -5001,5 +5257,19 @@ declare const whatsAppWebhookPayloadSchema: z.ZodObject<{
5001
5257
  }[];
5002
5258
  }>;
5003
5259
  type WhatsAppWebhookPayload = z.infer<typeof whatsAppWebhookPayloadSchema>;
5260
+ /**
5261
+ * O nome de perfil de quem mandou a mensagem.
5262
+ *
5263
+ * Casa por `wa_id`. Quando nenhum casa e há UM contato só, é dele: a Meta agrupa as mensagens de um
5264
+ * mesmo contato num `change`, e o `wa_id` nem sempre é idêntico ao `from` — no Brasil o nono dígito
5265
+ * aparece num e não no outro, e exigir igualdade perderia o nome exatamente nos números móveis.
5266
+ *
5267
+ * Com dois ou mais contatos sem casamento, devolve `undefined`: pendurar o nome errado numa ficha é
5268
+ * pior que ficha sem nome.
5269
+ */
5270
+ declare function resolveContactProfileName(params: {
5271
+ readonly contacts: readonly WhatsAppContact[] | undefined;
5272
+ readonly from: string;
5273
+ }): string | undefined;
5004
5274
 
5005
- export { whatsAppWebhookChangeSchema as A, whatsAppWebhookPayloadSchema as B, whatsAppWebhookValueSchema as C, WHATSAPP_WEBHOOK_FIELDS as W, type WhatsAppInteractive as a, type WhatsAppMedia as b, type WhatsAppMessage as c, type WhatsAppMessageEcho as d, type WhatsAppMessageStatusValue as e, type WhatsAppOrder as f, type WhatsAppPhoneNumberQualityUpdate as g, type WhatsAppQualityEvent as h, type WhatsAppStatus as i, type WhatsAppTemplateStatusEvent as j, type WhatsAppTemplateStatusUpdate as k, type WhatsAppWebhookChange as l, type WhatsAppWebhookField as m, type WhatsAppWebhookPayload as n, type WhatsAppWebhookValue as o, whatsAppMediaSchema as p, whatsAppMessageEchoSchema as q, whatsAppMessageSchema as r, whatsAppMessageStatusSchema as s, whatsAppOrderSchema as t, whatsAppPhoneNumberQualityUpdateSchema as u, whatsAppQualityEventSchema as v, whatsAppInteractiveSchema as w, whatsAppStatusSchema as x, whatsAppTemplateStatusEventSchema as y, whatsAppTemplateStatusUpdateSchema as z };
5275
+ export { whatsAppStatusSchema as A, whatsAppTemplateStatusEventSchema as B, whatsAppTemplateStatusUpdateSchema as C, whatsAppWebhookChangeSchema as D, whatsAppWebhookPayloadSchema as E, whatsAppWebhookValueSchema as F, WHATSAPP_WEBHOOK_FIELDS as W, type WhatsAppContact as a, type WhatsAppInteractive as b, type WhatsAppMedia as c, type WhatsAppMessage as d, type WhatsAppMessageEcho as e, type WhatsAppMessageStatusValue as f, type WhatsAppOrder as g, type WhatsAppPhoneNumberQualityUpdate as h, type WhatsAppQualityEvent as i, type WhatsAppStatus as j, type WhatsAppTemplateStatusEvent as k, type WhatsAppTemplateStatusUpdate as l, type WhatsAppWebhookChange as m, type WhatsAppWebhookField as n, type WhatsAppWebhookPayload as o, type WhatsAppWebhookValue as p, whatsAppInteractiveSchema as q, resolveContactProfileName as r, whatsAppMediaSchema as s, whatsAppMessageEchoSchema as t, whatsAppMessageSchema as u, whatsAppMessageStatusSchema as v, whatsAppContactSchema as w, whatsAppOrderSchema as x, whatsAppPhoneNumberQualityUpdateSchema as y, whatsAppQualityEventSchema as z };