{"_id":"@deijai/totvs-mingle-expo","_rev":"4-6cb0046d976f27ac17e19da883861673","name":"@deijai/totvs-mingle-expo","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@deijai/totvs-mingle-expo","version":"1.0.0","keywords":["totvs","mingle","react-native","expo","auth"],"author":{"name":"Deijai Miranda Almeida"},"license":"MIT","_id":"@deijai/totvs-mingle-expo@1.0.0","maintainers":[{"name":"deijai","email":"djairn18@gmail.com"}],"dist":{"shasum":"5ed5a32903e23127b78d2848ce3fcdbead39a927","tarball":"https://registry.npmjs.org/@deijai/totvs-mingle-expo/-/totvs-mingle-expo-1.0.0.tgz","fileCount":77,"integrity":"sha512-svY/YockMFrkVZWiQbhdhoRxDbUTAjTsIUXX4bwyAYL1DQ/eIkrj+S94+TS1FxpYEvIlQ7uHrUmzfF4N34y+2w==","signatures":[{"sig":"MEQCICVJ4M8fyaa4fLX0SXn066xwPE5fzKDK/dmxJfvRfx6SAiAo3uILIbINW3ICJdwmbUzMxwVesboGuxw4B2YdRW1Vww==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118942},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc"},"_npmUser":{"name":"deijai","email":"djairn18@gmail.com"},"_npmVersion":"11.11.0","description":"Wrapper do Mingle (TOTVS) para React Native com Expo","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/react":"^19.2.14","@types/react-native":"^0.72.8"},"peerDependencies":{"react":"^19.2.4","react-native":"^0.84.1"},"_npmOperationalInternal":{"tmp":"tmp/totvs-mingle-expo_1.0.0_1773946892900_0.35308376802191077","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@deijai/totvs-mingle-expo","version":"1.0.2","keywords":["totvs","mingle","react-native","expo","auth","sdk"],"author":{"name":"Deijaí Miranda"},"license":"MIT","_id":"@deijai/totvs-mingle-expo@1.0.2","maintainers":[{"name":"deijai","email":"djairn18@gmail.com"}],"dist":{"shasum":"cfab68687dac443eb81e957354537e3fab573577","tarball":"https://registry.npmjs.org/@deijai/totvs-mingle-expo/-/totvs-mingle-expo-1.0.2.tgz","fileCount":77,"integrity":"sha512-m9eBgYj7r6XMfwUXVx5j8+et3nOHRwBLjFbaghOKt1SgUoxagccrA6B48fSJQJScOH5Zr+i5nXFzNx0b3Uh7eQ==","signatures":[{"sig":"MEUCIQCnWXTTLpFlIWXq2mdPt/vSSy8g94TTwTN7dGxIa79XegIgavrqdBGv5hypZVnXW/qf+EobiWnaKtvAF/FxdeNRZLY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":118506},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","clean":"rimraf dist"},"_npmUser":{"name":"deijai","email":"djairn18@gmail.com"},"_npmVersion":"11.11.0","description":"Wrapper do Mingle (TOTVS) para React Native com Expo","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.4.0","@types/react":"^18.3.0","@types/react-native":"^0.73.0"},"peerDependencies":{"react":">=18 <20","react-native":">=0.74"},"_npmOperationalInternal":{"tmp":"tmp/totvs-mingle-expo_1.0.2_1773950204661_0.6713709463259343","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@deijai/totvs-mingle-expo","version":"1.1.0","keywords":["totvs","mingle","react-native","expo","auth","sdk"],"author":{"name":"Deijaí Miranda"},"license":"MIT","_id":"@deijai/totvs-mingle-expo@1.1.0","maintainers":[{"name":"deijai","email":"djairn18@gmail.com"}],"dist":{"shasum":"83f6096b2fafe8f97365669716c7258a29a7db01","tarball":"https://registry.npmjs.org/@deijai/totvs-mingle-expo/-/totvs-mingle-expo-1.1.0.tgz","fileCount":83,"integrity":"sha512-8rFzLZPk8YSbecNY0XeEtiz/JKPTjvWCob0cr5BGw91LHMZJE+qDz6eRGW7w6TJ/85UeXmE+IhmCOBX858wy0g==","signatures":[{"sig":"MEUCIQDBCvZvf58u3lYy8w0/hDrC2artSOlRkIQ4ISUI7j0diQIgUVMeVTUGheGWTKSNdWPvTBpXMEJBBMCoYPan6jMAAKA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":185279},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","clean":"rimraf dist"},"_npmUser":{"name":"deijai","email":"djairn18@gmail.com"},"_npmVersion":"11.11.0","description":"Wrapper do Mingle (TOTVS) para React Native com Expo","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.4.0","@types/react":"^18.3.0","@types/react-native":"^0.73.0"},"peerDependencies":{"react":">=18 <20","react-native":">=0.74"},"_npmOperationalInternal":{"tmp":"tmp/totvs-mingle-expo_1.1.0_1787271600353_0.4537772828929052","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"_id":"@deijai/totvs-mingle-expo@1.2.0","dist":{"shasum":"715416dd6db4691a0f633988b27ca151dccccd6f","tarball":"https://registry.npmjs.org/@deijai/totvs-mingle-expo/-/totvs-mingle-expo-1.2.0.tgz","fileCount":83,"integrity":"sha512-kJrGNiyy8ZoftTs4K1JtgXqpfMBl8XBJwP8Ihd+ibISPXeNRXF8vX5fueC6nOdG+LkYXTxtgI2nWh7eK9nT+tw==","signatures":[{"sig":"MEYCIQCbE6TLiK0oJOnBtmLLRpiGpuzQ6WKDrZjJYT0MqS3YEQIhAO9abvWUNFW2LHtgTUl0QTZq8mldIBo+PuABD1oIzQNX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDQG3Y9wYGYVhu2JqPLOFmTO3OFZIKxBHjkGizsT7awVQIgPUyvz6V2Rd86PzJ1LbVeH3x7feTCFuRmHKovdHlczAM="}],"unpackedSize":189465},"main":"dist/index.js","name":"@deijai/totvs-mingle-expo","types":"dist/index.d.ts","author":{"name":"Deijaí Miranda"},"license":"MIT","scripts":{"build":"tsc","clean":"rimraf dist"},"version":"1.2.0","_npmUser":{"name":"deijai","email":"djairn18@gmail.com"},"keywords":["totvs","mingle","react-native","expo","auth","sdk"],"_npmVersion":"11.11.0","description":"Wrapper do Mingle (TOTVS) para React Native com Expo","directories":{},"maintainers":[{"name":"deijai","email":"djairn18@gmail.com"}],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"devDependencies":{"rimraf":"^5.0.5","typescript":"^5.4.0","@types/react":"^18.3.0","@types/react-native":"^0.73.0"},"peerDependencies":{"react":">=18 <20","react-native":">=0.74"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/totvs-mingle-expo_1.2.0_1790450587792_0.4098631052685118"}}},"time":{"created":"2026-03-19T19:01:32.734Z","modified":"2026-09-26T19:23:08.022Z","1.0.0":"2026-03-19T19:01:33.048Z","1.0.2":"2026-03-19T19:56:44.798Z","1.1.0":"2026-08-21T00:20:00.503Z","1.2.0":"2026-09-26T19:23:07.883Z"},"author":{"name":"Deijaí Miranda"},"license":"MIT","keywords":["totvs","mingle","react-native","expo","auth","sdk"],"description":"Wrapper do Mingle (TOTVS) para React Native com Expo","maintainers":[{"name":"deijai","email":"djairn18@gmail.com"}],"readme":"# @deijai/totvs-mingle-expo\r\n\r\nWrapper do **TOTVS Mingle** para **React Native com Expo**, com suporte a:\r\n\r\n- login no Mingle (usuário/senha e OIDC)\r\n- persistência de sessão\r\n- refresh token\r\n- logout\r\n- push notifications (registro/desregistro de device token)\r\n- integração com gateway\r\n- métricas de uso\r\n- geolocalização\r\n- onboarding\r\n- provider e hook para React\r\n\r\nEste README foi escrito como **passo a passo de uso da lib**.\r\n\r\n---\r\n\r\n## 1. O que esta lib entrega\r\n\r\nA biblioteca já expõe estes recursos principais:\r\n\r\n- `MingleService`\r\n- `AuthService`\r\n- `GatewayService`\r\n- `MingleProvider`\r\n- `useMingleAuth`\r\n- `MingleHttpInterceptor`\r\n- `SessionService`\r\n\r\nEla também usa recursos do Expo internamente, como:\r\n\r\n- `expo-secure-store`\r\n- `expo-web-browser`\r\n- `expo-location`\r\n- `expo-device`\r\n- `expo-application`\r\n- `expo-constants`\r\n\r\n---\r\n\r\n## 2. Pré-requisitos\r\n\r\nAntes de usar a lib, seu projeto precisa ter:\r\n\r\n- **React Native** `>= 0.74`\r\n- **React** `>= 18 < 20`\r\n- projeto com **Expo**\r\n\r\nTambém é importante ter o endereço do servidor Mingle/TOTVS que será usado pela aplicação, por exemplo:\r\n\r\n- homologação\r\n- produção\r\n- ambiente próprio da empresa\r\n\r\n---\r\n\r\n## 3. Instalação\r\n\r\nInstale a biblioteca:\r\n\r\n```bash\r\nnpm install @deijai/totvs-mingle-expo\r\n```\r\n\r\nou\r\n\r\n```bash\r\nyarn add @deijai/totvs-mingle-expo\r\n```\r\n\r\nComo a lib depende de módulos do Expo, garanta que estas dependências existam no app consumidor:\r\n\r\n```bash\r\nnpx expo install expo-secure-store expo-web-browser expo-location expo-device expo-application expo-constants\r\nnpm install axios rxjs\r\n```\r\n\r\n---\r\n\r\n## 4. Configuração inicial\r\n\r\nA lib trabalha com uma configuração central contendo:\r\n\r\n- `app_identifier`\r\n- `server`\r\n- `environment`\r\n- `modules`\r\n\r\n### Exemplo de configuração\r\n\r\n```ts\r\nconst mingleConfig = {\r\n  app_identifier: 'SEU_APP_IDENTIFIER',\r\n  server: 'https://mingle.totvs.com.br',\r\n  environment: 'production',\r\n  modules: {\r\n    usage_metrics: true,\r\n    user_data: true,\r\n    web: false,\r\n  },\r\n};\r\n```\r\n\r\n### Campos principais\r\n\r\n#### `app_identifier`\r\nIdentificador do app no ecossistema Mingle.\r\n\r\n#### `server`\r\nURL base do servidor.\r\n\r\nExemplo:\r\n\r\n```ts\r\nserver: 'https://mingle.totvs.com.br'\r\n```\r\n\r\nA lib remove automaticamente a `/` final, se existir.\r\n\r\n#### `environment`\r\nPode ser usado para identificar o ambiente:\r\n\r\n```ts\r\nenvironment: 'development'\r\nenvironment: 'staging'\r\nenvironment: 'production'\r\n```\r\n\r\n#### `modules`\r\nPermite ativar ou customizar recursos opcionais.\r\n\r\nExemplo:\r\n\r\n```ts\r\nmodules: {\r\n  crashr: false,\r\n  ocr: false,\r\n  push_notification: false,\r\n  usage_metrics: true,\r\n  user_data: true,\r\n  web: false,\r\n}\r\n```\r\n\r\n---\r\n\r\n## 5. Forma mais simples de usar: com Provider\r\n\r\nA forma mais prática de usar a biblioteca em um app React Native com Expo é envolver sua aplicação com `MingleProvider`.\r\n\r\n### Exemplo no arquivo principal do app\r\n\r\n```tsx\r\nimport React from 'react';\r\nimport { MingleProvider } from '@deijai/totvs-mingle-expo';\r\nimport { AppRoutes } from './src/routes';\r\n\r\nconst mingleConfig = {\r\n  app_identifier: 'SEU_APP_IDENTIFIER',\r\n  server: 'https://mingle.totvs.com.br',\r\n  environment: 'production',\r\n  modules: {\r\n    usage_metrics: true,\r\n    user_data: true,\r\n    web: false,\r\n  },\r\n};\r\n\r\nexport default function App() {\r\n  return (\r\n    <MingleProvider config={mingleConfig}>\r\n      <AppRoutes />\r\n    </MingleProvider>\r\n  );\r\n}\r\n```\r\n\r\nQuando o provider sobe:\r\n\r\n- aplica a configuração\r\n- inicializa a sessão\r\n- tenta recuperar dados persistidos\r\n- disponibiliza o estado de autenticação para o resto do app\r\n\r\n---\r\n\r\n## 6. Como fazer login\r\n\r\nDepois de usar o provider, você pode consumir o hook `useMingleAuth()`.\r\n\r\n### Exemplo de tela de login\r\n\r\n```tsx\r\nimport React, { useState } from 'react';\r\nimport { Button, TextInput, View } from 'react-native';\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nexport function LoginScreen() {\r\n  const { login, loading, isAuthenticated, session } = useMingleAuth();\r\n\r\n  const [username, setUsername] = useState('');\r\n  const [password, setPassword] = useState('');\r\n  const [alias, setAlias] = useState('');\r\n\r\n  const handleLogin = async () => {\r\n    try {\r\n      await login(username, password, alias);\r\n      console.log('Usuário autenticado com sucesso');\r\n    } catch (error) {\r\n      console.error('Erro ao autenticar', error);\r\n    }\r\n  };\r\n\r\n  return (\r\n    <View style={{ padding: 16, gap: 12 }}>\r\n      <TextInput\r\n        placeholder=\"Usuário\"\r\n        value={username}\r\n        onChangeText={setUsername}\r\n      />\r\n\r\n      <TextInput\r\n        placeholder=\"Senha\"\r\n        secureTextEntry\r\n        value={password}\r\n        onChangeText={setPassword}\r\n      />\r\n\r\n      <TextInput\r\n        placeholder=\"Alias\"\r\n        value={alias}\r\n        onChangeText={setAlias}\r\n      />\r\n\r\n      <Button\r\n        title={loading ? 'Entrando...' : 'Entrar'}\r\n        onPress={handleLogin}\r\n      />\r\n    </View>\r\n  );\r\n}\r\n```\r\n\r\n### O que o login faz internamente\r\n\r\nAo chamar:\r\n\r\n```ts\r\nawait login(username, password, alias)\r\n```\r\n\r\nA lib:\r\n\r\n- envia credenciais para o endpoint de autenticação\r\n- salva token e refresh token\r\n- persiste a sessão com `expo-secure-store`\r\n- registra métricas de uso\r\n\r\n### Login com OIDC (via hook)\r\n\r\nQuando o `alias` está configurado para login federado (SSO), use `loginWithOidc` — ele abre o fluxo interativo (`expo-web-browser`) e já atualiza a sessão do hook sozinho:\r\n\r\n```tsx\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nexport function LoginScreen() {\r\n  const { loginWithOidc } = useMingleAuth();\r\n\r\n  const handleOidcLogin = async (alias: string) => {\r\n    const result = await loginWithOidc(alias);\r\n\r\n    if ('cancelled' in result && result.cancelled) {\r\n      // usuário fechou o navegador antes de concluir — não é um erro\r\n      return;\r\n    }\r\n\r\n    console.log('Login OIDC concluído');\r\n  };\r\n\r\n  return null; // ver exemplo completo mais abaixo\r\n}\r\n```\r\n\r\n`loginWithOidc` é a forma recomendada de disparar OIDC — ela já resolve o `discovery`/`redirectUri` internamente. Use `AuthService.beginInteractiveOidcAuth` diretamente (seção 16) só se precisar controlar `startUrl`/`returnUrl` manualmente.\r\n\r\n---\r\n\r\n## 7. Como verificar se o usuário está autenticado\r\n\r\nCom o hook:\r\n\r\n```tsx\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nexport function HomeScreen() {\r\n  const { ready, isAuthenticated, session } = useMingleAuth();\r\n\r\n  if (!ready) return null;\r\n\r\n  if (!isAuthenticated) {\r\n    return null;\r\n  }\r\n\r\n  console.log('Token atual:', session?.token);\r\n  console.log('Usuário:', session?.user);\r\n  console.log('Alias:', session?.set_alias);\r\n\r\n  return null;\r\n}\r\n```\r\n\r\n### Campos úteis da sessão\r\n\r\nA sessão pode conter, entre outros:\r\n\r\n- `token`\r\n- `refresh_token`\r\n- `user`\r\n- `user_login`\r\n- `set`\r\n- `set_alias`\r\n- `client`\r\n- `client_name`\r\n- `host`\r\n- `device_id`\r\n- `defaultHeaders`\r\n\r\n---\r\n\r\n## 8. Como renovar o token\r\n\r\nA própria lib possui método de refresh.\r\n\r\n### Com o hook\r\n\r\n```tsx\r\nconst { refreshSession } = useMingleAuth();\r\n\r\nawait refreshSession();\r\n```\r\n\r\n### Direto pelo serviço\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\nawait firstValueFrom(mingle.auth.refreshToken());\r\n```\r\n\r\n---\r\n\r\n## 9. Como fazer logout\r\n\r\n### Com o hook\r\n\r\n```tsx\r\nconst { logout } = useMingleAuth();\r\n\r\nawait logout();\r\n```\r\n\r\nO logout:\r\n\r\n- limpa sessão em memória\r\n- remove dados persistidos\r\n- registra métrica de saída\r\n\r\n---\r\n\r\n## 10. Como usar sem Provider\r\n\r\nSe você quiser controlar tudo manualmente, também pode usar `MingleService` diretamente.\r\n\r\n### Exemplo\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nasync function bootstrapMingle() {\r\n  mingle.setConfiguration({\r\n    app_identifier: 'SEU_APP_IDENTIFIER',\r\n    server: 'https://mingle.totvs.com.br',\r\n    environment: 'production',\r\n    modules: {\r\n      usage_metrics: true,\r\n      user_data: true,\r\n      web: false,\r\n    },\r\n  });\r\n\r\n  await mingle.init();\r\n}\r\n\r\nasync function doLogin() {\r\n  await firstValueFrom(\r\n    mingle.auth.login('usuario', 'senha', 'alias')\r\n  );\r\n\r\n  const session = mingle.getSessionInfo();\r\n  console.log(session.token);\r\n}\r\n```\r\n\r\n---\r\n\r\n## 11. Como fazer requisições autenticadas\r\n\r\nA lib oferece um método genérico de request.\r\n\r\n### Exemplo simples\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nconst response = await firstValueFrom(\r\n  mingle.request('GET', 'https://sua-api.com/endpoint', {\r\n    headers: {\r\n      Authorization: `Bearer ${mingle.getAccessToken()}`,\r\n    },\r\n  })\r\n);\r\n```\r\n\r\n### Usando URL relativa de API\r\n\r\nSe você usa uma rota relativa começando com `/api/`, o interceptor da lib pode montar a URL baseada no `server` configurado.\r\n\r\nExemplo:\r\n\r\n```ts\r\nmingle.request('GET', '/api/v1/minha-rota');\r\n```\r\n\r\n---\r\n\r\n## 12. Como usar o Gateway\r\n\r\nA biblioteca expõe `GatewayService`, que pode ser usada para chamadas integradas ao gateway do Mingle.\r\n\r\n### Exemplo conceitual\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nconst result = await firstValueFrom(\r\n  mingle.gateway.request('meu-endpoint')\r\n);\r\n```\r\n\r\n> O formato exato da chamada depende do endpoint gateway usado no seu ambiente TOTVS.\r\n\r\n---\r\n\r\n## 13. Como salvar e recuperar dados do usuário\r\n\r\nA lib já possui suporte para `user-data`.\r\n\r\n### Salvar dados\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nawait firstValueFrom(\r\n  mingle.saveUserData('preferences', {\r\n    theme: 'dark',\r\n    notifications: true,\r\n  })\r\n);\r\n```\r\n\r\n### Buscar dados\r\n\r\n```ts\r\nconst preferences = await firstValueFrom(\r\n  mingle.getUserData('preferences')\r\n);\r\n\r\nconsole.log(preferences);\r\n```\r\n\r\n---\r\n\r\n## 14. Como definir headers padrão\r\n\r\nVocê pode registrar headers que devem acompanhar as requisições.\r\n\r\n```ts\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nmingle.setDefaultHeaders([\r\n  { name: 'tenantId', value: 'empresa-filial-01' },\r\n  { name: 'x-app-version', value: '1.0.0' },\r\n]);\r\n```\r\n\r\nIsso é útil quando sua API exige cabeçalhos extras além do token.\r\n\r\n---\r\n\r\n## 15. Como usar o interceptor com Axios\r\n\r\nA lib exporta `MingleHttpInterceptor`, que pode ser acoplado a uma instância do Axios.\r\n\r\n### Exemplo\r\n\r\n```ts\r\nimport axios from 'axios';\r\nimport { MingleHttpInterceptor } from '@deijai/totvs-mingle-expo';\r\n\r\nconst api = axios.create();\r\n\r\nconst interceptor = new MingleHttpInterceptor();\r\ninterceptor.attach(api);\r\n\r\nconst response = await api.get('/api/v1/usuarios');\r\n```\r\n\r\n### O que o interceptor faz\r\n\r\nEle:\r\n\r\n- adiciona `Content-Type: application/json`\r\n- adiciona `Authorization: Bearer <token>` quando existir token\r\n- aplica `defaultHeaders`\r\n- converte rota relativa `/api/...` usando o `server` configurado\r\n- tenta refresh automático em caso de `401`\r\n\r\n---\r\n\r\n## 16. Como usar OIDC interativo\r\n\r\nA lib também possui suporte para autenticação OIDC via navegador.\r\n\r\n### Exemplo de abertura do fluxo\r\n\r\n```ts\r\nimport { AuthService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst auth = new AuthService();\r\n\r\nconst result = await auth.beginInteractiveOidcAuth({\r\n  startUrl: 'https://seu-provedor-oidc.com/auth',\r\n  returnUrl: 'meuapp://callback',\r\n});\r\n\r\nconsole.log(result);\r\n```\r\n\r\nSe o retorno for sucesso, a lib devolve:\r\n\r\n- `type`\r\n- `url`\r\n- `params`\r\n\r\nDepois disso, você pode complementar o fluxo com `getAuthForOIDC(...)`, conforme a necessidade da sua arquitetura.\r\n\r\n---\r\n\r\n## 17. Recuperação de senha e troca de senha\r\n\r\n### Recuperar senha\r\n\r\n```ts\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nawait firstValueFrom(\r\n  mingle.auth.passwordRecovery({\r\n    login: 'usuario',\r\n    alias: 'empresa01',\r\n    email: 'usuario@empresa.com',\r\n  })\r\n);\r\n```\r\n\r\n### Alterar senha do Protheus\r\n\r\n```ts\r\nawait firstValueFrom(\r\n  mingle.auth.changePwdProtheus('senhaAtual', 'novaSenha123')\r\n);\r\n```\r\n\r\n---\r\n\r\n## 18. Métricas de uso\r\n\r\nA lib possui suporte a métricas.\r\n\r\n### Registrar métrica manual\r\n\r\n```ts\r\nimport { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst mingle = MingleService.getInstance();\r\n\r\nmingle.registerMetric('APP_OPENED', {\r\n  screen: 'Home',\r\n});\r\n```\r\n\r\nQuando `usage_metrics` estiver desligado, a métrica pode ser armazenada localmente.\r\n\r\n---\r\n\r\n## 19. Geolocalização e device info\r\n\r\nA biblioteca possui suporte a geolocalização e informações do dispositivo.\r\n\r\n### Exemplo com `GeolocationService`\r\n\r\n```ts\r\nimport { GeolocationService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst geolocation = new GeolocationService();\r\nconst location = await geolocation.getCurrentLocation();\r\n\r\nconsole.log(location);\r\n```\r\n\r\n### Exemplo com `DeviceService`\r\n\r\n```ts\r\nimport { DeviceService, SessionService } from '@deijai/totvs-mingle-expo';\r\n\r\nconst session = SessionService.getInstance();\r\nconst deviceService = new DeviceService(session);\r\n\r\nconst device = await deviceService.getAllInfos();\r\nconsole.log(device);\r\n```\r\n\r\n---\r\n\r\n## 20. Push notifications\r\n\r\nA lib expõe `mingle.push`, que **só sabe conversar com o Mingle** (`POST`/`DELETE /api/v1/push/targets`) — ela não pede permissão nem resolve o token do dispositivo. Isso fica por conta do app, normalmente com `expo-notifications`:\r\n\r\n```bash\r\nnpx expo install expo-notifications\r\n```\r\n\r\n### Registrar o token (depois do login)\r\n\r\n```ts\r\nimport * as Notifications from 'expo-notifications';\r\nimport { firstValueFrom } from 'rxjs';\r\nimport type { MingleService } from '@deijai/totvs-mingle-expo';\r\n\r\nexport async function requestPushPermissionAndRegister(mingle: MingleService): Promise<void> {\r\n  try {\r\n    const { status: existingStatus } = await Notifications.getPermissionsAsync();\r\n    let finalStatus = existingStatus;\r\n\r\n    if (existingStatus !== 'granted') {\r\n      const { status } = await Notifications.requestPermissionsAsync();\r\n      finalStatus = status;\r\n    }\r\n    if (finalStatus !== 'granted') return;\r\n\r\n    // token bruto da plataforma (FCM no Android, APNs no iOS) — não o\r\n    // Expo push token, o Mingle espera o token nativo mesmo\r\n    const tokenResponse = await Notifications.getDevicePushTokenAsync();\r\n    const token = typeof tokenResponse.data === 'string' ? tokenResponse.data : String(tokenResponse.data);\r\n    if (!token) return;\r\n\r\n    await firstValueFrom(mingle.push.register(token));\r\n  } catch {\r\n    // best-effort: registro de push nunca deve bloquear login nem virar erro pro usuário\r\n  }\r\n}\r\n```\r\n\r\nDispare isso uma vez por sessão autenticada, por exemplo num hook que reage a `isAuthenticated`:\r\n\r\n```tsx\r\nimport { useEffect, useRef } from 'react';\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nexport function usePushRegistration(isAuthenticated: boolean): void {\r\n  const { mingle } = useMingleAuth();\r\n  const hasRun = useRef(false);\r\n\r\n  useEffect(() => {\r\n    if (!isAuthenticated) {\r\n      hasRun.current = false; // rearma pro próximo login\r\n      return;\r\n    }\r\n    if (hasRun.current) return;\r\n    hasRun.current = true;\r\n    void requestPushPermissionAndRegister(mingle);\r\n  }, [isAuthenticated, mingle]);\r\n}\r\n```\r\n\r\nO `hasRun` evita reabrir o prompt de permissão a cada re-render — sem ele, qualquer mudança de estado que re-renderize o componente dispararia o registro de novo.\r\n\r\n### Desregistrar o token (no logout — passo que costuma faltar)\r\n\r\nO registro em `/push/targets` é **aditivo por token**, não \"um alvo por dispositivo\". Se o app nunca desregistra, um segundo usuário que loga no mesmo aparelho continua recebendo as notificações do usuário anterior — inclusive alguém sem nenhuma permissão relacionada ao conteúdo da notificação. Por isso, todo fluxo de logout (manual ou por expiração de sessão) precisa chamar `mingle.push.unregister`:\r\n\r\n```ts\r\nexport async function unregisterPushToken(mingle: MingleService): Promise<void> {\r\n  try {\r\n    const { status } = await Notifications.getPermissionsAsync();\r\n    if (status !== 'granted') return;\r\n\r\n    const tokenResponse = await Notifications.getDevicePushTokenAsync();\r\n    const token = typeof tokenResponse.data === 'string' ? tokenResponse.data : String(tokenResponse.data);\r\n    if (!token) return;\r\n\r\n    await firstValueFrom(mingle.push.unregister(token));\r\n  } catch {\r\n    // best-effort — nunca deve travar o logout\r\n  }\r\n}\r\n```\r\n\r\n**Ordem importa**: `unregister` é uma chamada autenticada (usa o token da sessão atual no header). Ela precisa rodar **antes** de limpar a sessão, nunca depois:\r\n\r\n```ts\r\nasync function logout(mingle: MingleService, mingleLogout: () => Promise<void>) {\r\n  await unregisterPushToken(mingle); // 1º — sessão ainda válida\r\n  await mingleLogout();              // 2º — só agora limpa o token\r\n}\r\n```\r\n\r\nSe a ordem for invertida, a chamada de `unregister` vai falhar (sem `Authorization` válido) e o target antigo nunca é removido.\r\n\r\n---\r\n\r\n## 21. Como plugar implementações customizadas\r\n\r\nA configuração permite injetar adapters próprios para geolocalização, device, OCR e push.\r\n\r\n### Exemplo\r\n\r\n```ts\r\nconst mingleConfig = {\r\n  app_identifier: 'SEU_APP_IDENTIFIER',\r\n  server: 'https://mingle.totvs.com.br',\r\n  modules: {\r\n    geolocationInstance: {\r\n      getCurrentPosition: async () => {\r\n        return {\r\n          coords: {\r\n            latitude: -3.0,\r\n            longitude: -44.0,\r\n          },\r\n        };\r\n      },\r\n    },\r\n    deviceInstance: {\r\n      getDeviceUUID: async () => 'custom-device-id',\r\n      getDeviceInfos: async () => ({\r\n        uuid: 'custom-device-id',\r\n        model: 'Device X',\r\n        platform: 'android',\r\n      }),\r\n    },\r\n  },\r\n};\r\n```\r\n\r\nTambém é possível usar:\r\n\r\n```ts\r\nmingle.use(objetoDoPlugin)\r\n```\r\n\r\nAtualmente há tratamento para objetos com nome:\r\n\r\n- `GeolocationPlugin`\r\n- `DevicePlugin`\r\n\r\n---\r\n\r\n## 22. Exemplo completo de fluxo\r\n\r\n```tsx\r\nimport React from 'react';\r\nimport { Button, Text, View } from 'react-native';\r\nimport { MingleProvider, useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nconst config = {\r\n  app_identifier: 'SEU_APP_IDENTIFIER',\r\n  server: 'https://mingle.totvs.com.br',\r\n  environment: 'production',\r\n  modules: {\r\n    usage_metrics: true,\r\n    user_data: true,\r\n  },\r\n};\r\n\r\nfunction Content() {\r\n  const { ready, loading, isAuthenticated, session, login, logout } = useMingleAuth();\r\n\r\n  if (!ready) {\r\n    return <Text>Inicializando...</Text>;\r\n  }\r\n\r\n  return (\r\n    <View style={{ padding: 24, gap: 12 }}>\r\n      <Text>Autenticado: {isAuthenticated ? 'Sim' : 'Não'}</Text>\r\n      <Text>Usuário: {session?.user_login ?? '-'}</Text>\r\n\r\n      {!isAuthenticated ? (\r\n        <Button\r\n          title={loading ? 'Entrando...' : 'Login'}\r\n          onPress={() => login('usuario', 'senha', 'alias')}\r\n        />\r\n      ) : (\r\n        <Button\r\n          title={loading ? 'Saindo...' : 'Logout'}\r\n          onPress={logout}\r\n        />\r\n      )}\r\n    </View>\r\n  );\r\n}\r\n\r\nexport default function App() {\r\n  return (\r\n    <MingleProvider config={config}>\r\n      <Content />\r\n    </MingleProvider>\r\n  );\r\n}\r\n```\r\n\r\n---\r\n\r\n## 23. Estrutura recomendada no app consumidor\r\n\r\nUma organização simples e saudável seria:\r\n\r\n```text\r\nsrc/\r\n  services/\r\n    api.ts\r\n    mingle.ts\r\n  providers/\r\n    app-provider.tsx\r\n  screens/\r\n    login-screen.tsx\r\n    home-screen.tsx\r\n  hooks/\r\n    use-session.ts\r\n```\r\n\r\nSugestão prática:\r\n\r\n- deixe a configuração Mingle centralizada em um único arquivo\r\n- use o `MingleProvider` no topo da árvore\r\n- encapsule regras de login/logout em hooks ou stores do app\r\n- use o interceptor para evitar repetir token manualmente\r\n\r\n### Padrão usado em produção: não espalhe `useMingleAuth()` pelo app\r\n\r\nChamar `useMingleAuth()` direto em cada tela acopla toda a aplicação à lib — trocar de estratégia de auth (ex: adicionar um modo demo/offline) vira um refactor grande. O padrão adotado nos apps TOTVS que já usam esta lib é isolar `useMingleAuth()` atrás de UM adapter com uma interface própria do app:\r\n\r\n```ts\r\n// src/services/auth/AuthGateway.ts — a interface que o resto do app conhece\r\nexport type AuthGateway = {\r\n  ready: boolean;\r\n  loading: boolean;\r\n  session: Session | null;\r\n  isAuthenticated: boolean;\r\n  login: (login: string, password: string, alias: string) => Promise<void>;\r\n  loginWithOidc: (alias: string) => Promise<{ cancelled: boolean }>;\r\n  logout: () => Promise<void>;\r\n  refreshSession: () => Promise<void>;\r\n};\r\n```\r\n\r\n```ts\r\n// src/services/auth/RealAuthGateway.ts — delega tudo pra lib, não reimplementa nada\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\nimport type { AuthGateway } from './AuthGateway';\r\n\r\nexport function useRealAuthGateway(): AuthGateway {\r\n  const { ready, loading, session, isAuthenticated, login, loginWithOidc, logout, refreshSession } = useMingleAuth();\r\n\r\n  return {\r\n    ready, loading, session, isAuthenticated, logout, refreshSession,\r\n    login: async (loginValue, password, alias) => { await login(loginValue, password, alias); },\r\n    loginWithOidc: async (alias) => {\r\n      const result = await loginWithOidc(alias);\r\n      return { cancelled: 'cancelled' in result && result.cancelled === true };\r\n    },\r\n  };\r\n}\r\n```\r\n\r\n```ts\r\n// src/services/auth/useAuthGateway.ts — troca a implementação em UM lugar só\r\nimport { useDemoModeStore } from '@/store/useDemoModeStore';\r\nimport { useRealAuthGateway } from './RealAuthGateway';\r\nimport { useDemoAuthGateway } from './DemoAuthGateway'; // fixtures locais, sem rede\r\n\r\nexport function useAuthGateway(): AuthGateway {\r\n  const isDemoMode = useDemoModeStore((s) => s.isDemoMode);\r\n  const real = useRealAuthGateway();\r\n  const demo = useDemoAuthGateway();\r\n  return isDemoMode ? demo : real;\r\n}\r\n```\r\n\r\nCom isso, telas de login/home/settings só conhecem `AuthGateway` — nunca importam `@deijai/totvs-mingle-expo` diretamente. Trocar de provedor de auth, adicionar modo demo, ou (no limite) trocar de lib inteira, vira mudança em 2-3 arquivos, não em todo o app.\r\n\r\n### Logout único, com push desregistrado na ordem certa\r\n\r\nCentralize logout num hook único, chamado de qualquer lugar (tela, timeout de sessão, botão de configurações) — nunca duplique a sequência:\r\n\r\n```ts\r\n// src/hooks/useLogout.ts\r\nimport { useMingleAuth } from '@deijai/totvs-mingle-expo';\r\nimport { unregisterPushToken } from '@/services/push/pushNotifications';\r\nimport { useAuthGateway } from '@/services/auth/useAuthGateway';\r\n\r\nexport function useLogout(): () => Promise<void> {\r\n  const gateway = useAuthGateway();\r\n  const { mingle } = useMingleAuth();\r\n\r\n  return async () => {\r\n    await unregisterPushToken(mingle); // 1º — sessão ainda válida (ver seção 20)\r\n    await gateway.logout();            // 2º — limpa sessão, cache de queries, etc.\r\n  };\r\n}\r\n```\r\n\r\nIsso garante que **todo** caminho de logout — botão manual, expiração de sessão detectada por um 401 de qualquer endpoint autenticado — passa pela mesma sequência, sem duplicar (e sem esquecer) o desregistro de push.\r\n\r\n---\r\n\r\n## 24. Erros comuns\r\n\r\n### 1. Esquecer de chamar a inicialização\r\nSe não usar o provider, chame:\r\n\r\n```ts\r\nawait mingle.init();\r\n```\r\n\r\n### 2. Não informar `app_identifier`\r\nSem isso, parte do fluxo de autenticação pode falhar.\r\n\r\n### 3. Não configurar o `server`\r\nSem a URL base correta, os endpoints não serão resolvidos corretamente.\r\n\r\n### 4. Tentar fazer chamada autenticada sem sessão\r\nAntes de chamar endpoints protegidos, garanta que existe token salvo na sessão.\r\n\r\n### 5. Não instalar dependências do Expo usadas pela lib\r\nComo a biblioteca usa módulos nativos do Expo, o app consumidor precisa ter essas dependências instaladas.\r\n\r\n### 6. Chamar `mingle.push.unregister` depois de `logout()`\r\nA chamada é autenticada — se a sessão já foi limpa, o `unregister` falha silenciosamente (best-effort) e o target antigo fica registrado pra sempre. Sempre desregistre **antes** de limpar a sessão (seção 20).\r\n\r\n### 7. Registrar push sem guarda contra re-render\r\nSem um `hasRun`/flag equivalente, qualquer re-render com `isAuthenticated === true` reabre o prompt de permissão e chama `register` de novo.\r\n\r\n---\r\n\r\n## 25. Resumo do fluxo ideal\r\n\r\n### Fluxo padrão\r\n\r\n1. Instalar a lib\r\n2. Instalar dependências do Expo e utilitárias\r\n3. Configurar `app_identifier` e `server`\r\n4. Envolver o app com `MingleProvider`\r\n5. (recomendado) Isolar `useMingleAuth()` atrás de um `AuthGateway` próprio do app (seção 23)\r\n6. Registrar o push token quando `isAuthenticated` vira `true` (seção 20)\r\n7. Centralizar logout num hook único: desregistra push → só então `logout()` (seções 20 e 23)\r\n8. Usar `MingleHttpInterceptor` nas APIs autenticadas\r\n9. Consumir gateway, user-data e métricas conforme necessário\r\n\r\n---\r\n\r\n## 26. Exemplo mínimo de uso\r\n\r\n```tsx\r\nimport React from 'react';\r\nimport { Button } from 'react-native';\r\nimport { MingleProvider, useMingleAuth } from '@deijai/totvs-mingle-expo';\r\n\r\nconst config = {\r\n  app_identifier: 'SEU_APP_IDENTIFIER',\r\n  server: 'https://mingle.totvs.com.br',\r\n};\r\n\r\nfunction Screen() {\r\n  const { login } = useMingleAuth();\r\n\r\n  return (\r\n    <Button\r\n      title=\"Login\"\r\n      onPress={() => login('usuario', 'senha', 'alias')}\r\n    />\r\n  );\r\n}\r\n\r\nexport default function App() {\r\n  return (\r\n    <MingleProvider config={config}>\r\n      <Screen />\r\n    </MingleProvider>\r\n  );\r\n}\r\n```\r\n\r\n---\r\n\r\n## 27. Build da biblioteca\r\n\r\nPara gerar a build local da lib:\r\n\r\n```bash\r\nnpm install\r\nnpm run build\r\n```\r\n\r\nA saída será gerada em:\r\n\r\n```text\r\ndist/\r\n```\r\n\r\n---\r\n\r\n## 28. Publicação e uso interno\r\n\r\nSe a biblioteca for publicada em registry privado ou usada internamente na empresa, mantenha neste README:\r\n\r\n- versão da lib\r\n- ambiente suportado\r\n- dependências obrigatórias\r\n- exemplos de integração\r\n- fluxo de autenticação esperado\r\n\r\nIsso reduz muito o esforço de adoção por outros times.\r\n\r\n---\r\n\r\n## 29. Licença\r\n\r\nMIT\r\n","readmeFilename":"README.md"}