@omnizapi/connect 1.0.1 → 1.0.3

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ ## [1.0.3] - 2026-09-11
4
+
5
+ ### Correcao
6
+
7
+ - O login nativo do Meta WhatsApp so acontece com `direct: true`, e nesse caso o SDK nao reserva a janela `about:blank` no clique. Na 1.0.2 a reserva consumia o unico popup que o navegador concede por clique, o dialogo da Meta era bloqueado e a tentativa ficava ativa ate o timeout (`CONNECTION_IN_PROGRESS` no clique seguinte). Sem `direct`, todo Meta WhatsApp usa a janela reservada e navega para `/oauth/proxy-cloud-api` da plataforma, inclusive na origem do frontend de conexao e em canais com `appCustom`; o proxy faz o login nativo com um clique novo. `appCustom` e a origem da pagina deixam de selecionar o nativo.
8
+ - Com `direct` em canal que nao e Meta WhatsApp, ou quando a pagina nao pode rodar o nativo, a janela do proxy e aberta na navegacao, apos a configuracao do canal, e pode ser bloqueada pelo navegador; documentado.
9
+
10
+ ## [1.0.2] - 2026-09-10
11
+
12
+ Primeira versao documentada neste changelog; nao reconstitui o historico de releases anteriores.
13
+
14
+ ### API e ciclo de vida
15
+
16
+ - `ConnectionOptions.signal?: AbortSignal` permite interromper `connect` com `OmnizapiError.code === "ABORTED"` e limpeza dos recursos da tentativa, sem expor `signal.reason`. Nao desfaz autorizacoes no provedor nem operacoes ja recebidas pelo backend.
17
+ - Uma tentativa ativa por pagina, inclusive entre clientes; reserva de popup `about:blank` no gesto e navegacao da mesma janela apos validar a configuracao. A selecao de fluxo nativo por `appCustom` fecha a janela provisoria; o gesto exigido pelo SDK Meta ainda depende de homologacao externa.
18
+ - Quarentena nativa preservada quando o login termina sem callback Meta, inclusive por timeout ou abort. Callback de cancelamento ou tardio libera somente a tentativa dona, sem exigir reload para todo cancelamento.
19
+ - Inicializacao rastreada pelo SDK Facebook reutilizada para o mesmo `appId` numerico, sem reinicializar silenciosamente o SDK do host; conflitos de app e inicializacao preexistente desconhecida degradam para o fluxo proxy na janela reservada (abaixo).
20
+ - Chamadas externas ao `FB.init` observado invalidam o app conhecido, inclusive entre versoes da biblioteca. Timeouts inconclusivos de scripts externos impedem atribuir proveniencia propria a um carregamento tardio; recursos do host nao sao removidos.
21
+ - `getListMessengerPages` permanece `Promise<unknown>`: o schema do servico externo nao foi confirmado. Os tipos publicos continuam importados da raiz de `@omnizapi/connect`. A chamada agora aceita um `AbortSignal` opcional como terceiro argumento; aborts rejeitam com `ABORTED` (antes `NETWORK_ERROR`) e sinais invalidos com `INVALID_OPTIONS`.
22
+ - Conflito de app Meta ou SDK Meta do host com inicializacao desconhecida nao rejeita mais com `INVALID_CONFIGURATION`: a tentativa degrada para o fluxo proxy na janela reservada. A quarentena de login nativo (`CONNECTION_IN_PROGRESS`) nao degrada. Para canais `appCustom`, o fallback exige o dominio/redirects da plataforma cadastrados no app do cliente.
23
+ - Um `FB.login` que lanca excecao sincrona libera imediatamente a quarentena nativa (nenhum dialogo abriu, nenhum callback chegara), permitindo nova tentativa sem recarregar a pagina.
24
+ - A janela `about:blank` passa a ser reservada no clique para todos os canais, inclusive com `direct: true`: `direct` deixa de impedir a reserva e apenas solicita o fluxo nativo no WhatsApp Meta, corrigindo o `POPUP_BLOCKED` de `direct` em outros canais. Fechar a janela reservada antes da navegacao nao cancela a tentativa; `popup_closed` so ocorre quando o fluxo ja depende da janela.
25
+ - A comparacao de `allowOrigins` normaliza cada entrada com `new URL(origin).origin`, aceitando entradas com barra final, path ou porta padrao.
26
+ - As URLs de `/connect/telegram` e `/connect/whatsapp-web` incluem `pk` (a chave publica), permitindo ao frontend de conexao restringir o `targetOrigin` da resposta as origens autorizadas do canal em vez de `*`.
27
+
28
+ ### Exemplos e documentacao
29
+
30
+ - Criacao/cache de clientes movidos para o `try` do clique nos exemplos TypeScript, React, Angular e Vue, permitindo exibir erros de configuracao sem falhar na importacao/renderizacao.
31
+ - Exemplo de erros com mensagens tipadas exaustivas, inclusive `ABORTED`, e cancelamento controlado apenas durante a autorizacao. React usa `useRef` e cleanup com `AbortController`, sem atualizacoes apos desmontagem nem memoizacao desnecessaria.
32
+ - Mensagens de retry ajustadas para nao exigir reload indiscriminado nem recomendar repetir uma finalizacao cujo estado no backend e desconhecido. Nenhum exemplo registra tokens ou erros brutos.
33
+ - Scripts CDN e links UNPKG do README e do exemplo vanilla fixados na versao do manifesto; os exemplos locais sao os mesmos incluidos no pacote.
34
+ - Documentacao de `appCustom` preservada e ampliada com limites de inicializacao compartilhada e de gesto nativo; `PROVIDER_ERROR` nao e prometido para toda recusa de dominio pela Meta.
35
+ - Nota explicita de privacidade: `state.currentUrl` permanece a URL completa, inclusive query e fragmento, com risco de exposicao de tokens/dados sensiveis. Reduzir a origem depende de verificacao dos proxies e nao foi implementado nesta rodada.
36
+ - Licenca MIT completa adicionada com copyright 2026 FourPixel IT, preservando a autoria.
37
+
38
+ ### Verificacao e release
39
+
40
+ - Fluxo de desenvolvimento documentado com Node.js 22 via `.nvmrc`, `npm ci` e `npm run check` para lint, unitarios, build limpo e smoke tests.
41
+ - Protecao de `pack`/`publish` via `prepack` e verificacao de defaults de producao Omnizapi, sem URLs customizadas embutidas no artefato de release. `npm run build` continua aceitando variaveis customizadas explicitas.
42
+ - Testes de navegador documentados para Chromium, Firefox e WebKit, com preparacao previa dos binarios Playwright; CI de verificacoes sem publicacao automatica. Testes simulados nao substituem integracao com Meta/proxies reais.
43
+ - Sincronizacao dos links versionados por `scripts/sync-version.mjs` em futuras alteracoes aprovadas com `npm version <nova-versao> --no-git-tag-version`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FourPixel IT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  SDK Omnizapi para conectar canais Meta WhatsApp, Messenger, Instagram, Telegram e Z-API WhatsApp em aplicacoes web. Coleta o resultado da autorizacao; seu backend valida e finaliza a conexao. Nao envie secret keys ao frontend.
4
4
 
5
+ Versao atual: **1.0.3**. As mudancas desta versao estao no [changelog](https://unpkg.com/browse/@omnizapi/connect@1.0.3/CHANGELOG.md), disponivel com o pacote publicado.
6
+
5
7
  ## Instalacao e importacao
6
8
 
7
9
  ```bash
@@ -29,30 +31,30 @@ CommonJS: `const { Omnizapi } = require("@omnizapi/connect")`.
29
31
  No navegador, o bundle expoe o global `Omnizapi`:
30
32
 
31
33
  ```html
32
- <script src="https://unpkg.com/@omnizapi/connect/dist/omnizapi.min.js"></script>
34
+ <script src="https://unpkg.com/@omnizapi/connect@1.0.3/dist/omnizapi.min.js"></script>
33
35
  ```
34
36
 
35
- Fixe uma versao publicada e homologada no CDN antes do deploy. Imports ESM/CommonJS e `newClient` sao seguros em SSR; `connect` exige navegador e rejeita com `BROWSER_REQUIRED` no servidor. O bundle de script e exclusivo do navegador.
37
+ O CDN usa uma versao fixa; homologue sua integracao antes do deploy. Imports ESM/CommonJS e `newClient` sao seguros em SSR; `connect` exige navegador e rejeita com `BROWSER_REQUIRED` no servidor. O bundle de script e exclusivo do navegador.
36
38
 
37
39
  ## Uso
38
40
 
39
- ```ts
40
- const client = Omnizapi.newClient({ publicKey: "sua-public-key" });
41
- ```
41
+ Crie/reutilize o cliente com `Omnizapi.newClient({ publicKey: "sua-public-key" })` dentro do `try` do handler de clique, para que `INVALID_CONFIGURATION` tambem seja tratado pela UI.
42
42
 
43
- Dispare `client.connect({ channelId })` em um clique, nunca durante renderizacao, montagem ou importacao. Os exemplos completos incluem UI, `try/catch/finally`, tratamento de `reason` e envio ao backend:
43
+ Dispare `client.connect({ channelId })` diretamente no clique, sem outro `await` antes, nunca durante renderizacao, montagem ou importacao. Os exemplos completos incluem UI, `try/catch/finally`, tratamento de `reason` e envio ao backend:
44
44
 
45
45
  | Exemplo | Uso |
46
46
  | --- | --- |
47
- | [TypeScript basico](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/basic.ts) | Botao e mensagem de status no DOM |
48
- | [HTML com CDN](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/vanilla.html) | Pagina sem bundler |
49
- | [React / Next.js](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/react.tsx) | `'use client'`, cliente por componente via `useState` lazy |
50
- | [Angular](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/angular.ts) | Componente com guarda de navegador para SSR |
51
- | [Vue](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/vue.vue) | SFC com guarda de navegador para SSR |
52
- | [Opcoes](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/with-options.ts) | SANDBOX, URLs explicitas, logo, fluxo padrao/direto e timeout |
53
- | [Erros](https://unpkg.com/browse/@omnizapi/connect@1.0.1/examples/error-handling.ts) | Mensagens para todos os motivos e codigos tipados |
47
+ | [TypeScript basico](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/basic.ts) | Botao e mensagem de status no DOM |
48
+ | [HTML com CDN](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/vanilla.html) | Pagina sem bundler |
49
+ | [React / Next.js](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/react.tsx) | `'use client'`, UI de conexao por componente |
50
+ | [Angular](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/angular.ts) | Componente com guarda de navegador para SSR |
51
+ | [Vue](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/vue.vue) | SFC com guarda de navegador para SSR |
52
+ | [Opcoes](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/with-options.ts) | SANDBOX, URLs explicitas, logo, fluxo padrao/direto e timeout |
53
+ | [Erros](https://unpkg.com/browse/@omnizapi/connect@1.0.3/examples/error-handling.ts) | Mensagens para todos os motivos e codigos tipados |
54
+
55
+ Os links abrem o codigo-fonte dos exemplos da versao 1.0.3, incluido no pacote npm. Nao sao demos hospedadas: adapte as chaves, o canal e o backend na sua aplicacao.
54
56
 
55
- Os links abrem o codigo-fonte dos exemplos da versao 1.0.1, incluido no pacote npm. Nao sao demos hospedadas: adapte as chaves, o canal e o backend na sua aplicacao.
57
+ Os arquivos `examples/error-handling.ts` e `examples/react.tsx` demonstram `AbortSignal`. No React, o cliente fica em `useRef`, e so e criado no `try` do clique; o cleanup de `useEffect` aborta a tentativa/requisicao pendente sem atualizar a UI desmontada. O exemplo de erros usa `Record<OmnizapiErrorCode, string>` exaustivo e permite cancelar apenas a autorizacao, nao a finalizacao no backend. Nao ha botao para limpar a quarentena nativa.
56
58
 
57
59
  Os exemplos usam `/api/connect-channel` como rota **da sua aplicacao**, nao fornecida por este pacote. Ela deve autenticar a sessao, validar o resultado e responder com HTTP 2xx somente quando a finalizacao tiver sido confirmada. Os exemplos aguardam `fetch` e verificam `response.ok` antes de exibir sucesso. Adapte a autenticacao e a protecao CSRF ao seu backend. Nao registre resultados, tokens, codigos OAuth ou erros brutos que possam conter URLs sensiveis.
58
60
 
@@ -85,13 +87,20 @@ Precedencia por URL: **props > `OMNIZAPI_API_URL` / `OMNIZAPI_FRONT_URL` no buil
85
87
  | Campo | Tipo | Descricao |
86
88
  | --- | --- | --- |
87
89
  | `channelId` | `string` | Obrigatorio; canal a conectar |
88
- | `direct` | `boolean` | Solicita Meta WhatsApp Embedded Signup sem o popup proxy; nao se aplica aos outros canais. O SDK tambem escolhe o fluxo nativo com `appCustom` ou na origem do frontend de conexao |
90
+ | `direct` | `boolean` | Solicita o Meta WhatsApp Embedded Signup nativo na propria pagina, sem o popup proxy. Com `direct` o SDK **nao reserva** janela no clique, porque o dialogo da Meta abre a sua e navegadores concedem um popup por clique. Use so em pagina onde o clique e dedicado a conexao (o frontend de conexao faz isso em `/oauth/proxy-cloud-api`); em outros canais, ou quando a pagina nao pode rodar o nativo, a janela do proxy e aberta na navegacao e pode ser bloqueada. Sem `direct`, todo Meta WhatsApp usa a janela reservada, inclusive com `appCustom` e na origem do frontend de conexao |
89
91
  | `getQRCode` | `() => Promise<{ connected?: boolean; value?: string }>` | Callback opcional para integracao QR com o frontend externo; veja os limites abaixo |
90
92
  | `timeoutMs` | `number` | Prazo total positivo e finito em ms, ate `2147483647`; padrao **600000 (10 minutos)** |
93
+ | `signal` | `AbortSignal` | Opcional; permite interromper a tentativa via `AbortController` |
91
94
 
92
95
  HTTP e carregamento do SDK Facebook tem limite de **30 segundos**, respeitando o prazo total restante da tentativa. O POST ao seu backend nao faz parte desse prazo e precisa de politica propria de timeout.
93
96
 
94
- Ha **uma tentativa ativa por pagina**, inclusive entre clientes diferentes. Outra chamada concorrente rejeita com `CONNECTION_IN_PROGRESS`; nao implemente retry automatico para abrir popups. Mesmo a partir de um clique, um popup aberto depois de um `await` pode ser bloqueado: trate `POPUP_BLOCKED` e permita nova tentativa pelo usuario.
97
+ Ha **uma tentativa ativa por pagina**, inclusive entre clientes diferentes. Outra chamada concorrente rejeita com `CONNECTION_IN_PROGRESS`; nao implemente retry automatico para abrir popups.
98
+
99
+ O SDK reserva um popup `about:blank` durante o clique, para qualquer canal sem `direct`, antes de aguardar a configuracao do canal; apos validar a resposta, navega a mesma janela. A janela provisoria e fechada ao encerrar a tentativa. Com `direct` nao ha reserva: o dialogo nativo da Meta usa o popup que o clique concede. Fechar a janela reservada antes da navegacao nao cancela a tentativa: o fechamento so resulta em `popup_closed` quando o fluxo ja depende da janela (apos a navegacao) ou quando ela e encontrada fechada na hora de navegar. Ainda trate `POPUP_BLOCKED` e permita nova tentativa por clique. A reserva nao transfere o gesto ao `FB.login`: o fluxo nativo, apos carregar a configuracao/SDK Meta, ainda exige homologacao externa com navegadores reais.
100
+
101
+ **Cancelamento:** passe um sinal novo por tentativa. Se o sinal ja estiver abortado ou for abortado enquanto `connect` estiver pendente, a Promise rejeita com `OmnizapiError.code === "ABORTED"`, nao resolve com `reason: "cancelled"`. O SDK encerra requisicoes pendentes, timers e listeners da tentativa, fecha o popup que controla e restaura seus globais temporarios sem sobrescrever alteracoes do host, nem expor `signal.reason`. Scripts/callbacks de terceiros nao sao removidos; a observacao de um script Meta externo compartilhado pode continuar ate carregar, falhar ou atingir o limite de 30 segundos.
102
+
103
+ Abort nao desfaz uma autorizacao na Meta, nao fecha necessariamente o dialogo nativo e nao remove a quarentena de um login nativo ainda sem callback. Depois que `connect` termina, abortar esse sinal nao cancela automaticamente seu POST; o React passa o sinal tambem ao `fetch`, mas nem isso desfaz operacoes ja recebidas pelo servidor. Confira o estado no backend antes de repetir uma finalizacao sem confirmacao.
95
104
 
96
105
  O retorno e uma uniao discriminada por `success`, nao uma confirmacao de persistencia no seu backend:
97
106
 
@@ -113,35 +122,40 @@ Resultados negativos resolvem a Promise e nao significam sempre cancelamento:
113
122
  | `origin_not_allowed` | Origem da aplicacao nao autorizada para o canal |
114
123
  | `unsupported_channel` | Tipo de canal nao suportado |
115
124
 
125
+ Uma pagina servida com `Cross-Origin-Opener-Policy: same-origin` faz o navegador cortar a referencia da janela popup; o SDK reporta `popup_closed` (ou `POPUP_BLOCKED`), indistinguivel de um fechamento pelo usuario. Nao ha como diferenciar os dois casos via JavaScript: permita nova tentativa por clique e, se possivel, ajuste a politica da pagina de conexao.
126
+
116
127
  Falhas tecnicas rejeitam com `OmnizapiError`; use `instanceof OmnizapiError` e `error.code`, nao o texto da mensagem:
117
128
 
118
129
  | Codigo | Significado |
119
130
  | --- | --- |
120
131
  | `BROWSER_REQUIRED` | Operacao exige navegador |
121
132
  | `CONNECTION_IN_PROGRESS` | Tentativa ativa nesta pagina ou login Meta nativo anterior incompleto; veja os limites abaixo |
122
- | `INVALID_CONFIGURATION` | Props ou configuracao de ambiente invalidas |
123
- | `INVALID_OPTIONS` | Opcoes da operacao invalidas, como `channelId` com tipo incorreto ou timeout invalido |
133
+ | `INVALID_CONFIGURATION` | Props, ambiente ou APIs de navegador invalidos; conflitos de app/inicializacao do SDK Meta degradam para o fluxo proxy, sem rejeitar |
134
+ | `INVALID_OPTIONS` | Opcoes da operacao invalidas, como `channelId` com tipo incorreto, timeout ou sinal invalido |
124
135
  | `NETWORK_ERROR` | Falha de transporte |
125
136
  | `HTTP_ERROR` | Resposta HTTP sem sucesso |
126
137
  | `INVALID_RESPONSE` | Resposta da API invalida |
127
138
  | `POPUP_BLOCKED` | Navegador impediu a abertura do popup |
128
139
  | `TIMEOUT` | Prazo de operacao excedido |
140
+ | `ABORTED` | Tentativa interrompida pelo `AbortSignal` da aplicacao, com mensagem segura |
129
141
  | `SDK_LOAD_FAILED` | Falha ao carregar/inicializar SDK do provedor |
130
142
  | `PROVIDER_ERROR` | Erro reportado pelo provedor |
131
143
 
132
- ### `client.getListMessengerPages(channelId, code): Promise<unknown>`
144
+ ### `client.getListMessengerPages(channelId, code, signal?): Promise<unknown>`
133
145
 
134
- Consulta as paginas Messenger usando o codigo OAuth e o canal. Valide o retorno antes de acessa-lo: o schema externo ainda nao foi confirmado, portanto o SDK nao publica DTO de pagina. Nao use cast para inventar esse contrato, nem registre o codigo ou a resposta. A chamada tambem pode rejeitar com erro tecnico e tem timeout HTTP de 30 segundos.
146
+ Consulta as paginas Messenger usando o codigo OAuth e o canal. Valide o retorno antes de acessa-lo: o schema externo ainda nao foi confirmado, portanto o SDK nao publica DTO de pagina. Nao use cast para inventar esse contrato, nem registre o codigo ou a resposta. A chamada tambem pode rejeitar com erro tecnico e tem timeout HTTP de 30 segundos. O terceiro argumento aceita um `AbortSignal` opcional; um sinal abortado (antes ou durante a chamada) rejeita com `OmnizapiError.code === "ABORTED"`, e um sinal invalido rejeita com `INVALID_OPTIONS`.
135
147
 
136
148
  ## Protocolo de popup
137
149
 
138
150
  Este contrato exige deploy coordenado do frontend/proxy e backend externos; nenhum desses servicos e alterado neste repositorio. Nao ha fallback para mensagens sem os identificadores exigidos.
139
151
 
140
- 1. O SDK gera `attemptId` por tentativa. Popups abertos diretamente no `frontUrl` recebem `attemptId` na query. No OAuth Messenger/Instagram, o `state` JSON e `{ currentUrl, attemptId, channelId }`; o proxy deve preserva-lo e vincula-lo a sessao autorizada, ao canal e ao tenant. `state` e query nao sao prova de autorizacao por si so.
152
+ 1. O SDK gera `attemptId` por tentativa. Popups abertos diretamente no `frontUrl` recebem `attemptId` na query; as rotas `/connect/telegram` e `/connect/whatsapp-web` tambem recebem `pk` (a chave publica) na query, permitindo ao frontend consultar as origens autorizadas do canal e restringir o `targetOrigin` da resposta. No OAuth Messenger/Instagram, o `state` JSON e `{ currentUrl, attemptId, channelId }`; o proxy deve preserva-lo e vincula-lo a sessao autorizada, ao canal e ao tenant. `state` e query nao sao prova de autorizacao por si so.
141
153
  2. A pagina final deve estar na origem exata de `frontUrl` e emitir da **propria janela popup** aberta pelo SDK, nao de iframe, outra janela ou backend. Ela responde ao `window.opener` usando `postMessage` com `type: 'after-connect'`, `attemptId`, `channelId`, `success` e as credenciais aplicaveis. `attemptId` e `channelId` devem corresponder exatamente a tentativa ativa.
142
154
  3. O SDK verifica a origem exata do frontend, `event.source` igual ao popup ativo e os dois identificadores. O emissor usa `targetOrigin` igual a origem exata da aplicacao autorizada, nunca wildcard e nunca uma origem derivada de query/state nao validados.
143
155
  4. Sucesso dos proxies Meta exige `code`; Telegram exige `botToken`. `Z_API_WHATSAPP` pode retornar sucesso autenticado sem credenciais, mas o backend deve confirmar a conexao real para aquele canal/tenant. Para negativo, envie `success: false` e o `reason` tipado aplicavel, sem credenciais.
144
156
 
157
+ **Privacidade de `state`: `currentUrl` continua sendo `window.location.href` COMPLETO, incluindo caminho, query e fragmento.** Esta rodada nao reduz esse valor a origem: a compatibilidade dos proxies com uma URL minimizada ainda e desconhecida. Tokens ou outros dados sensiveis na query/fragmento da pagina podem assim ser copiados para o `state` OAuth e expostos ao provedor, proxy, historico ou logs de URLs. Evite iniciar a conexao em paginas com esses dados e nao registre `state` nem URLs completas. Fica pendente verificar com os responsaveis pelos proxies se aceitam apenas a origem antes de propor qualquer mudanca coordenada desse contrato.
158
+
145
159
  Mensagens com origem, janela, identificadores ou formato incorretos sao ignoradas; a tentativa continua aguardando conclusao, fechamento ou timeout. Uma mensagem de sucesso sem a credencial exigida resulta em `not_completed`.
146
160
 
147
161
  Trecho ilustrativo **no frontend externo**, apos o servidor validar a sessao e a autorizacao da tentativa. `authorizedSession` representa dados validados pelo servidor, nao um DTO deste SDK; nao a construa lendo parametros da URL sem validacao:
@@ -160,7 +174,7 @@ if (window.opener) {
160
174
 
161
175
  O Meta Embedded Signup **nativo** nao fornece `attemptId` nem uma referencia customizada da janela emissora (`event.source`) para correlacao. Ele usa a allowlist exata `https://www.facebook.com` / `https://web.facebook.com` e o callback `FB.login`. Nao se pode garantir o isolamento de eventos nativos tardios entre tentativas; essas verificacoes nao sao garantia absoluta de seguranca.
162
176
 
163
- Um login nativo fica em quarentena ate a Meta responder o `FB.login` (com codigo, cancelamento ou erro) ou ate a tentativa ter sucesso. Cancelou ou fechou o dialogo? A Meta responde e a proxima tentativa nativa e liberada na hora. So um login que a Meta nunca respondeu, como um timeout com o dialogo ainda aberto, mantem novas tentativas nativas em `CONNECTION_IN_PROGRESS` ate **recarregar a pagina**. Essa restricao evita atribuir a uma nova tentativa a resposta tardia de um dialogo anterior; nao se aplica aos popups proxy.
177
+ Um login nativo fica em quarentena ate a Meta responder o callback `FB.login` (com codigo, cancelamento ou erro) ou ate a tentativa ter sucesso. O callback, inclusive tardio, libera apenas a quarentena da tentativa a que pertence; nao libera a de outra tentativa. Fechar/cancelar o dialogo ou receber um evento de cancelamento nao garante que esse callback ja tenha chegado. Se um login terminar por timeout, abort ou cancelamento **sem callback**, novas tentativas nativas continuam em `CONNECTION_IN_PROGRESS`: aguarde o callback ou **recarregue a pagina** para tentar outro login nativo. Um callback recebido de cancelamento nao exige reload. Um `FB.login` que falha ao iniciar (excecao sincrona, sem abrir dialogo e sem callback futuro) libera a quarentena imediatamente, sem exigir reload. Essa restricao reduz o risco de atribuir a uma nova tentativa a resposta tardia de um dialogo anterior; nao se aplica aos popups proxy.
164
178
 
165
179
  Durante uma tentativa, apenas `__omnizapiPublicKey`, `__omnizapiCurrentChannel` e `__omnizapiGetQrCode` sao publicados temporariamente para o frontend externo. Uma funcao QR no `window` da aplicacao nao atravessa origens nem e serializada por `postMessage`: o frontend precisa de uma integracao explicitamente autorizada e compativel com a politica de mesma origem. Este repositorio nao valida por si so o fluxo Z-API real nem confirma essa integracao externa.
166
180
 
@@ -168,30 +182,62 @@ Durante uma tentativa, apenas `__omnizapiPublicKey`, `__omnizapiCurrentChannel`
168
182
 
169
183
  Por padrao o canal usa o app da Meta da plataforma, e a Meta so enxerga o `frontUrl` (`app.hubmessage.io` ou `app.omni.z-api.io`): o login do WhatsApp e o retorno do OAuth do Messenger e do Instagram acontecem na janela da plataforma. Nesse caso o seu dominio nao precisa de nada na Meta, so na allowlist de origens do canal.
170
184
 
171
- Quando o canal tem app proprio (`appCustom` no `sdk-info`), o SDK muda de comportamento: o login do WhatsApp Meta (Embedded Signup) roda **na sua propria pagina**, com o seu `appId` e `configId`, e o OAuth do Messenger e do Instagram continua voltando para a plataforma. Entao o **seu** app da Meta precisa conhecer os dois lados:
185
+ Quando o canal tem app proprio (`appCustom` no `sdk-info`), o login do WhatsApp Meta (Embedded Signup) continua na janela da plataforma (`/oauth/proxy-cloud-api`), mas com o **seu** `appId` e `configId`, e o OAuth do Messenger e do Instagram tambem volta para a plataforma. Entao o **seu** app da Meta precisa conhecer o dominio da plataforma e, se voce usar `direct` na sua pagina, tambem o seu:
172
186
 
173
187
  | Onde no app da Meta | O que cadastrar |
174
188
  | --- | --- |
175
- | Facebook Login > Configuracoes > Dominios permitidos para o SDK do JavaScript | Todas as origens onde o seu site chama `connect` (ex.: `https://www.suaempresa.com.br`), e o `frontUrl` da plataforma se voce tambem conecta pelo painel |
189
+ | Facebook Login > Configuracoes > Dominios permitidos para o SDK do JavaScript | O `frontUrl` da plataforma (ex.: `https://app.omni.z-api.io`) e, se voce usar `direct`, todas as origens onde o seu site chama `connect` |
176
190
  | Facebook Login > Configuracoes > URIs de redirecionamento do OAuth validos | `${frontUrl}/oauth/proxy-messenger` e `${frontUrl}/oauth/proxy-instagram` da marca que voce usa (ex.: `https://app.omni.z-api.io/oauth/proxy-messenger`) |
177
- | Configuracoes basicas > Dominios do app | O dominio do seu site e o da plataforma |
191
+ | Configuracoes basicas > Dominios do app | O dominio da plataforma e, com `direct`, o do seu site |
178
192
  | WhatsApp > Embedded Signup | A configuracao cujo id e o `configId` cadastrado na plataforma; o app precisa ter os produtos WhatsApp, Messenger e Instagram habilitados conforme os canais que vai conectar |
179
193
 
180
- Sem o dominio do seu site nos dominios do SDK, a Meta recusa o `FB.login` com erro de dominio e o SDK rejeita com `PROVIDER_ERROR`. Sem os redirects, o OAuth do Messenger e do Instagram para na tela da Meta com "URL bloqueada". Sem a origem do seu site na allowlist do canal, o SDK resolve com `origin_not_allowed` antes de abrir qualquer janela.
194
+ Sem o dominio do seu site nos dominios do SDK, a Meta pode recusar o `FB.login`. `PROVIDER_ERROR` depende de a Meta reportar um erro ao SDK; nao e possivel garantir esse codigo para toda falha de dominio. Sem os redirects corretos, o OAuth do Messenger e do Instagram pode ser bloqueado pela Meta. Sem a origem do seu site na allowlist do canal, o SDK resolve com `origin_not_allowed` antes de navegar para a autorizacao; uma janela provisoria ja pode ter sido reservada e sera fechada.
195
+
196
+ **Inicializacao Meta:** o SDK inicializa uma vez e reutiliza o mesmo `appId` somente quando essa inicializacao foi rastreada pelo proprio SDK. Nao reinicializa silenciosamente o `FB` compartilhado com outro app: quando a pagina nao pode rodar o nativo com seguranca — `FB` do host com inicializacao desconhecida, app conflitante, `appId` retornado pela API que nao e uma string numerica valida ou inicializacao que nao pode ser observada — a tentativa **degrada para o fluxo proxy** na janela reservada, em vez de rejeitar com `INVALID_CONFIGURATION`. Se a janela reservada tiver sido fechada ou bloqueada, a tentativa termina com `popup_closed` ou `POPUP_BLOCKED`. A quarentena de login nativo (`CONNECTION_IN_PROGRESS`) nao degrada: ela protege a atribuicao de callbacks tardios da Meta.
197
+
198
+ Com o fallback, um `FB` preexistente do host (inclusive de outro app) nao impede mais a conexao: o login acontece na janela da plataforma. Para canais com `appCustom`, isso exige que o **seu** app da Meta conheca o dominio da plataforma, conforme a tabela acima; sem os redirects e dominios corretos, a Meta pode bloquear o fluxo proxy do seu app. Nao reinicialize o `FB` por fora depois que o SDK rastrear seu app. Nao presuma que `direct: false` force proxy nem que `direct: true` garanta nativo: `appCustom`, a origem do frontend e agora a disponibilidade do nativo na pagina tambem decidem o fluxo.
199
+
200
+ Em SDKs carregados pela biblioteca, chamadas externas ao `FB.init` atual sao encaminhadas normalmente, mas invalidam o app conhecido: uma conexao nativa posterior degrada para o proxy em vez de usar o app errado. Referencias ao `init` original salvas antes dessa observacao nao podem ser monitoradas. Se um script externo expirar sem falha conclusiva, seu carregamento ainda pode terminar: novos SDKs nao recebem proveniencia propria ate recarregar a pagina. O script do host nao e removido.
201
+
202
+ ## Desenvolvimento e verificacao
203
+
204
+ Use **Node.js 22**, conforme `.nvmrc`, e as dependencias do lockfile:
205
+
206
+ ```bash
207
+ nvm use
208
+ npm ci
209
+ npm run check
210
+ ```
211
+
212
+ `npm run check` executa lint, testes unitarios, build limpo e smoke tests do pacote. Ele limpa os overrides `OMNIZAPI_API_URL` / `OMNIZAPI_FRONT_URL` no ambiente dos subprocessos, sem alterar o ambiente do chamador. A verificacao de release exige os padroes de producao Omnizapi (`https://api.omni.z-api.io` e `https://app.omni.z-api.io`), sem URLs customizadas embutidas no artefato. O lifecycle `prepack` protege automaticamente `npm pack` e `npm publish`; nao use `--ignore-scripts` para contornar essa protecao na preparacao de uma release. A CI faz verificacoes, nao publicacao automatica.
213
+
214
+ Para os testes locais de navegador, prepare antes os binarios dos tres engines:
215
+
216
+ ```bash
217
+ npm exec playwright install chromium firefox webkit
218
+ npm run test:browser
219
+ ```
220
+
221
+ `test:browser` cobre Chromium, Firefox e WebKit usando o artefato ja compilado: execute `npm run check` antes, pois esse teste nao recompila o SDK. Testes com provedores simulados nao homologam o SDK Meta, os proxies, credenciais ou canais reais; o fluxo nativo e os servicos externos continuam exigindo teste de integracao.
222
+
223
+ `npm run build` continua permitindo builds customizados com variaveis explicitas `OMNIZAPI_API_URL` e `OMNIZAPI_FRONT_URL`. Isso nao substitui o build com defaults de producao exigido pelo guard de release. As props `apiUrl` / `frontUrl` continuam sendo o modo de configurar o consumidor sem recompilar o SDK.
224
+
225
+ O hook de versao `scripts/sync-version.mjs` sincroniza os links UNPKG e scripts CDN do README/exemplo vanilla em futuras execucoes aprovadas de `npm version <nova-versao> --no-git-tag-version`. Isso nao publica o pacote.
181
226
 
182
227
  ## Checklist de deploy
183
228
 
184
- - [ ] Publicar `@omnizapi/connect` com exports default/named `Omnizapi`, tipos atualizados e `dist/omnizapi.min.js`; atualizar imports, script tags e configuracao dos consumidores em conjunto.
185
- - [ ] Configurar `OMNIZAPI_API_URL` / `OMNIZAPI_FRONT_URL` no build ou `apiUrl` / `frontUrl` nas props; conferir producao, staging e ambas as URLs de sandbox.
229
+ - [ ] Antes de uma publicacao futura aprovada, executar as verificacoes e conferir exports default/named `Omnizapi`, tipos na raiz e `dist/omnizapi.min.js`; manter imports, versoes CDN e configuracao dos consumidores coordenados.
230
+ - [ ] Conferir os defaults de producao no artefato de release. Para consumidores customizados, configurar `apiUrl` / `frontUrl` nas props; conferir staging e ambas as URLs de sandbox. Variaveis no build ficam restritas a builds customizados explicitos.
186
231
  - [ ] Manter na API as rotas existentes `GET /instances/:channelId/sdk-info` e `POST /v1/channels/:channelId/list-messenger-pages`, com autenticacao por chave publica, schema validado e sem exposicao de secrets.
187
232
  - [ ] Manter no frontend `/oauth/proxy-cloud-api`, `/oauth/proxy-messenger`, `/oauth/proxy-instagram`, `/connect/telegram` e `/connect/whatsapp-web`, inclusive ao usar uma URL base com prefixo.
188
233
  - [ ] Conferir a logo customizada e o asset padrao `${frontUrl}/logos/SVG/Ativo%2016.svg`, acessiveis por HTTPS e com identidade Omnizapi.
189
234
  - [ ] Autorizar as origens exatas da aplicacao por canal e configurar CORS da API para essas origens, metodos e headers (`Authorization`, `Content-Type`). Validacao client-side nao substitui autorizacao no servidor.
190
235
  - [ ] Cadastrar os redirects Meta exatos `${frontUrl}/oauth/proxy-messenger` e `${frontUrl}/oauth/proxy-instagram`, alem de dominios/configuracoes do Embedded Signup e app IDs corretos.
191
236
  - [ ] Implementar preservacao de `state`, sessao autorizada e protocolo `after-connect` acima em todas as rotas; confirmar origem final, janela emissora, `attemptId`, `channelId` e `targetOrigin` exatos. Conferir politicas de navegador/COOP que possam remover `opener`.
237
+ - [ ] Revisar exposicao de query/fragmento em `state.currentUrl`, que permanece completo. Verificar com os proxies a compatibilidade com origem apenas antes de qualquer futura minimizacao; nao assumir suporte.
192
238
  - [ ] Validar no backend sessao, CSRF, canal/tenant e credenciais especificas do provedor antes de finalizar; trocar/armazenar tokens somente no servidor, limitar repeticao/replay e nao aceitar `success: true` do navegador como prova suficiente.
193
- - [ ] Homologar cancelamento, fechamento/bloqueio de popup, concorrencia, timeout, mensagens de origem/janela/tentativa incorretas e falhas HTTP; validar em servicos reais a integracao QR e cada canal, inclusive Z-API. Os exemplos nao substituem essa homologacao.
239
+ - [ ] Homologar abort, cancelamento com/sem callback Meta (inclusive tardio), fechamento/bloqueio de popup, concorrencia, timeout, conflitos de app ID (que degradam para o fluxo proxy), mensagens de origem/janela/tentativa incorretas e falhas HTTP; validar em servicos reais o gesto do login nativo, a integracao QR e cada canal, inclusive Z-API. Os exemplos nao substituem essa homologacao.
194
240
 
195
241
  ## Licenca
196
242
 
197
- MIT - FourPixel IT. Autor: FourPixel IT.
243
+ MIT - Copyright (c) 2026 FourPixel IT. Autor: FourPixel IT. Texto completo no arquivo local `LICENSE` e na [licenca do pacote](https://unpkg.com/browse/@omnizapi/connect@1.0.3/LICENSE) apos a publicacao correspondente.