{"_id":"@avasapp/react-native-otp-autofill","_rev":"6-ffb0f5e25ff3f14fc4c956aa63a6efb3","name":"@avasapp/react-native-otp-autofill","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@avasapp/react-native-otp-autofill","version":"1.0.0","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","_id":"@avasapp/react-native-otp-autofill@1.0.0","maintainers":[{"name":"athik.dev","email":"athik@avas.dev"}],"homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"dist":{"shasum":"2f3c5439360be4e50cd3c01a8732770ddf6c6c53","tarball":"https://registry.npmjs.org/@avasapp/react-native-otp-autofill/-/react-native-otp-autofill-1.0.0.tgz","fileCount":55,"integrity":"sha512-mmBmmY787yfUC5AWx+kc/b/IkSIlTDLYHmhuveu/uokV87sVQiLhbgPCuHKJ+t18nSZY+2P1mWXCuaXtW+9GrA==","signatures":[{"sig":"MEYCIQCbt/SrC9MrFj3Y5tDAIuN/ikbWAXYUZoa+cDFh/U6mXgIhAOllbn1+NaHhzki40/aDFb5wpepQDwPqf+lBL0JNmw/R","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":384905},"main":"build/index.js","type":"commonjs","types":"build/index.d.ts","gitHead":"78c5967117f29ef573190b15e972fcc008f7d1a4","scripts":{"lint":"bunx expo-module lint","test":"bunx expo-module test","build":"bunx expo-module build","clean":"bunx expo-module clean","prepare":"bunx expo-module prepare","open:ios":"xed example/ios","expo-module":"bunx expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"bunx expo-module prepublishOnly"},"_npmUser":{"name":"athik.dev","email":"athik@avas.dev"},"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"_npmVersion":"11.3.0","description":"Automatic SMS Verification with the SMS Retriever API","directories":{"example":"example"},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"expo":"^53.0.19","eslint":"^9.32.0","@types/react":"~19.0.14","react-native":"0.79.5","eslint-config-expo":"^9.2.0","eslint-plugin-react":"^7.37.5","expo-module-scripts":"^4.1.9","@typescript-eslint/parser":"^8.38.0","eslint-plugin-react-native":"^5.0.0","eslint-plugin-react-compiler":"^19.1.0-rc.2","@typescript-eslint/eslint-plugin":"^8.38.0"},"peerDependencies":{"expo":"*","react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-otp-autofill_1.0.0_1754458542833_0.6491087826165831","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@avasapp/react-native-otp-autofill","version":"1.0.1","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","_id":"@avasapp/react-native-otp-autofill@1.0.1","maintainers":[{"name":"athik.dev","email":"athik@avas.dev"}],"homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"dist":{"shasum":"fe695d9b3d8f23b7c6b696464cf14072cb21773d","tarball":"https://registry.npmjs.org/@avasapp/react-native-otp-autofill/-/react-native-otp-autofill-1.0.1.tgz","fileCount":55,"integrity":"sha512-3jMG47X52r4J0LkYiO3Gjgf8q81+XiawriGXeAnWf+VqKKVnsbjtSdVxla3a9rzPFCG73jgZ0brkEZgFHFh40w==","signatures":[{"sig":"MEYCIQDlleJ+qHfwtf8pOMWtf/biz9y53A68UoWkngurF0BC5QIhAKVTUVGdVEe6zbE9oWJLtmzSQ76HexxIThkisgAZ/zKJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":391990},"main":"build/index.js","type":"commonjs","types":"build/index.d.ts","gitHead":"66868ea18c4ece4883133be4d5462d71c00c7a0f","scripts":{"lint":"bunx expo-module lint","test":"bunx expo-module test","build":"bunx expo-module build","clean":"bunx expo-module clean","prepare":"bunx expo-module prepare","open:ios":"xed example/ios","expo-module":"bunx expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"bunx expo-module prepublishOnly"},"_npmUser":{"name":"athik.dev","email":"athik@avas.dev"},"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"_npmVersion":"11.3.0","description":"Automatic SMS Verification with the SMS Retriever API","directories":{"example":"example"},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"expo":"^53.0.19","eslint":"^9.32.0","@types/react":"~19.0.14","react-native":"0.79.5","eslint-config-expo":"^9.2.0","eslint-plugin-react":"^7.37.5","expo-module-scripts":"^4.1.9","@typescript-eslint/parser":"^8.38.0","eslint-plugin-react-native":"^5.0.0","eslint-plugin-react-compiler":"^19.1.0-rc.2","@typescript-eslint/eslint-plugin":"^8.38.0"},"peerDependencies":{"expo":"*","react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-otp-autofill_1.0.1_1754460202405_0.7406691318571317","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@avasapp/react-native-otp-autofill","version":"1.0.2","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","_id":"@avasapp/react-native-otp-autofill@1.0.2","maintainers":[{"name":"athik.dev","email":"athik@avas.dev"}],"homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"dist":{"shasum":"c090510ff6b4f8b0d8cdac78eb308f27db29b02f","tarball":"https://registry.npmjs.org/@avasapp/react-native-otp-autofill/-/react-native-otp-autofill-1.0.2.tgz","fileCount":55,"integrity":"sha512-bHpDvRoDiYTkb2K4coPUMIpfvMd15IOl5PtpmI3FNtm5jFgJgc3f4Px/YydYBV1gY/yAXEKdTepnuT4jh0wHXg==","signatures":[{"sig":"MEYCIQC/5NHLjUmFsIK0aXQzdNWpQbhexsX6GtlylwETzWxlQAIhAMhAXwcT4Bo/Ix74XLUMIwfNjccjgYzW3gtSkhn8HClg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":392687},"main":"build/index.js","type":"commonjs","types":"build/index.d.ts","gitHead":"43ae4e0d2f6c9f5f0afd842b3806480db790aaf5","scripts":{"lint":"bunx expo-module lint","test":"bunx expo-module test","build":"bunx expo-module build","clean":"bunx expo-module clean","prepare":"bunx expo-module prepare","open:ios":"xed example/ios","expo-module":"bunx expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"bunx expo-module prepublishOnly"},"_npmUser":{"name":"athik.dev","email":"athik@avas.dev"},"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"_npmVersion":"11.3.0","description":"Automatic SMS Verification with the SMS Retriever API","directories":{"example":"example"},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"expo":"^53.0.19","eslint":"^9.32.0","@types/react":"~19.0.14","react-native":"0.79.5","eslint-config-expo":"^9.2.0","eslint-plugin-react":"^7.37.5","expo-module-scripts":"^4.1.9","@typescript-eslint/parser":"^8.38.0","eslint-plugin-react-native":"^5.0.0","eslint-plugin-react-compiler":"^19.1.0-rc.2","@typescript-eslint/eslint-plugin":"^8.38.0"},"peerDependencies":{"expo":"*","react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-otp-autofill_1.0.2_1754902325796_0.6896914827456009","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@avasapp/react-native-otp-autofill","version":"1.0.3","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","_id":"@avasapp/react-native-otp-autofill@1.0.3","maintainers":[{"name":"athik.dev","email":"athik@avas.dev"}],"homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"dist":{"shasum":"0bb77303487e6a8bb5b4145b38cb48470934e0e3","tarball":"https://registry.npmjs.org/@avasapp/react-native-otp-autofill/-/react-native-otp-autofill-1.0.3.tgz","fileCount":55,"integrity":"sha512-+JQXMFoaQNBSBQoVAjEN1qW4SS60An28n7RYCzRDQ5Yyv3doiYMs7VheLcUDqgyCrPgEFsz3il/JyNPwvK4ulw==","signatures":[{"sig":"MEUCIDwnEMUZFBsVMPdvpEqUNkp03L+mE55bH2AssNh37vuSAiEA8PZqUoe1AO0OpFT0E7FEaCSzYSJxJnRCSIf5rKYXrsA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390564},"main":"build/index.js","type":"commonjs","types":"build/index.d.ts","gitHead":"443735bc7ed3ae1b925fac8c93dd96dd24b5c6c9","scripts":{"lint":"bunx expo-module lint","test":"bunx expo-module test","build":"bunx expo-module build","clean":"bunx expo-module clean","prepare":"bunx expo-module prepare","open:ios":"xed example/ios","expo-module":"bunx expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"bunx expo-module prepublishOnly"},"_npmUser":{"name":"athik.dev","email":"athik@avas.dev"},"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"_npmVersion":"11.17.0","description":"Automatic SMS Verification with the SMS Retriever API","directories":{"example":"example"},"_nodeVersion":"26.5.0","_hasShrinkwrap":false,"devDependencies":{"expo":"^53.0.19","eslint":"^9.32.0","@types/react":"~19.0.14","react-native":"0.79.5","eslint-config-expo":"^9.2.0","eslint-plugin-react":"^7.37.5","expo-module-scripts":"^4.1.9","@typescript-eslint/parser":"^8.38.0","eslint-plugin-react-native":"^5.0.0","eslint-plugin-react-compiler":"^19.1.0-rc.2","@typescript-eslint/eslint-plugin":"^8.38.0"},"peerDependencies":{"expo":"*","react":"*","react-native":"*"},"_npmOperationalInternal":{"tmp":"tmp/react-native-otp-autofill_1.0.3_1783582837201_0.8231803175702901","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@avasapp/react-native-otp-autofill","version":"1.1.0","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","_id":"@avasapp/react-native-otp-autofill@1.1.0","maintainers":[{"name":"athik.dev","email":"athik@avas.dev"}],"homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"dist":{"shasum":"b88921ed50ac9c4180171e0f46c39d3bb42bea52","tarball":"https://registry.npmjs.org/@avasapp/react-native-otp-autofill/-/react-native-otp-autofill-1.1.0.tgz","fileCount":48,"integrity":"sha512-jjy6qg1WtQsXXncZSUpxdN9zMAIk1Ix3LtxTrHXzsm0GgxtSJyPTkpGEoJCZb4bRnMMxOiuz7CJcbzRlVjeADw==","signatures":[{"sig":"MEUCIDxQ4egvN/cMapaFK44Kn6Q7uvBM7reUZDpAFCPeaTgPAiEAp6MpUmKcP/8IYvyGcB1qwhTDuLOwwIl8Eq8ahnijdpo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85932},"main":"build/index.js","type":"commonjs","types":"build/index.d.ts","gitHead":"02fac0402a6cf7e4d995c610c0a6890b80599de9","scripts":{"lint":"eslint src","test":"bunx expo-module test","build":"bunx expo-module build","clean":"bunx expo-module clean","prepare":"bunx expo-module prepare","open:ios":"xed example/ios","expo-module":"bunx expo-module","open:android":"open -a \"Android Studio\" example/android","prepublishOnly":"bunx expo-module prepublishOnly"},"_npmUser":{"name":"athik.dev","email":"athik@avas.dev"},"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"_npmVersion":"11.17.0","description":"Automatic SMS Verification with the SMS Retriever API","directories":{"example":"example"},"_nodeVersion":"26.5.0","_hasShrinkwrap":false,"devDependencies":{"expo":"^53.0.19","eslint":"^9.32.0","@types/react":"~19.0.14","react-native":"0.79.5","eslint-config-expo":"^9.2.0","eslint-plugin-react":"^7.37.5","expo-module-scripts":"^4.1.9","@typescript-eslint/parser":"^8.38.0","eslint-plugin-react-native":"^5.0.0","eslint-plugin-react-compiler":"^19.1.0-rc.2","@typescript-eslint/eslint-plugin":"^8.38.0"},"peerDependencies":{"expo":">=50.0.0","react":">=18.0.0","react-native":">=0.74.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native-otp-autofill_1.1.0_1784022037237_0.6486436455618203","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2025-08-06T05:35:42.681Z","modified":"2026-07-22T11:34:16.431Z","1.0.0":"2025-08-06T05:35:43.039Z","1.0.1":"2025-08-06T06:03:22.595Z","1.0.2":"2025-08-11T08:52:05.979Z","1.0.3":"2026-07-09T07:40:37.346Z","1.1.0":"2026-07-14T09:40:37.378Z"},"bugs":{"url":"https://github.com/avas-app/react-native-android-otp-autofill/issues"},"author":{"url":"https://github.com/avas-app","name":"Avas App","email":"engineering@avas.dev"},"license":"MIT","homepage":"https://github.com/avas-app/react-native-android-otp-autofill#readme","keywords":["react-native","expo","react-native-otp-autofill","AvasOtpAutofill"],"repository":{"url":"git+https://github.com/avas-app/react-native-android-otp-autofill.git","type":"git"},"description":"Automatic SMS Verification with the SMS Retriever API","maintainers":[{"email":"npm.drainage506@passmail.net","name":"crockalet"},{"email":"athik@avas.dev","name":"athik.dev"}],"readme":"# React Native OTP Autofill\n\nAn Expo module for automatic SMS verification using Android SMS Retriever API.\n\n[![NPM Version](https://img.shields.io/npm/v/%40avasapp%2Freact-native-otp-autofill?style=for-the-badge&color=%23EA3F00)](https://www.npmjs.com/package/@avasapp/react-native-otp-autofill)\n[![npm bundle size](https://img.shields.io/bundlephobia/min/%40avasapp%2Freact-native-otp-autofill?style=for-the-badge&color=%23FFFFFF)](https://bundlephobia.com/package/@avasapp/react-native-otp-autofill)\n[![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40avasapp%2Freact-native-otp-autofill?style=for-the-badge&color=%23FFFFFF)](https://bundlephobia.com/package/@avasapp/react-native-otp-autofill)\n![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/avas-app/react-native-android-otp-autofill/publish.yml?style=for-the-badge)\n\n## Requirements\n\n- Android API 23+ (24+ on Expo SDK 54+)\n- Google Play Services\n- Expo SDK 50+\n\n## Features\n\n- ✅ Automatic SMS verification using Android SMS Retriever API\n- ✅ App signature hash generation for SMS verification\n- ✅ OTP extraction from SMS messages\n- ✅ Event-based listener system\n- ✅ TypeScript support\n- ✅ Expo modules API\n\n## Installation\n\nThis module is available as an npm package. To use it in your Expo/React Native app:\n\n### npm\n\n```bash\nnpm install @avasapp/react-native-otp-autofill\n```\n\n### bun\n\n```bash\nbun add @avasapp/react-native-otp-autofill\n```\n\n### yarn\n\n```bash\nyarn add @avasapp/react-native-otp-autofill\n```\n\n### Quick Start\n\nAfter installation, you can use the React hooks for the simplest integration:\n\n```typescript\nimport { useGetHash, useOtpListener } from '@avasapp/react-native-otp-autofill'\n\n// In your component\nconst { hash } = useGetHash()\nconst { startListener, receivedOtp } = useOtpListener()\n```\n\n## Usage\n\n### React Hooks API (Recommended)\n\nThe module provides React hooks for easy integration with modern React apps:\n\n#### useGetHash Hook\n\n```typescript\nimport React from 'react'\nimport { Button, Text, View } from 'react-native'\nimport { useGetHash } from '@avasapp/react-native-otp-autofill'\n\nconst AppHashComponent = () => {\n  const { hash, loading, error, refetch } = useGetHash({\n    onSuccess: (hash) => {\n      console.log('App hash loaded:', hash)\n    },\n    onError: (error) => {\n      console.error('Failed to get app hash:', error)\n    },\n  })\n\n  if (loading) return <Text>Loading app hash...</Text>\n  if (error) return <Text>Error: {error.message}</Text>\n\n  return (\n    <View>\n      <Text>App Hash: {hash}</Text>\n      <Button title=\"Refresh Hash\" onPress={refetch} />\n    </View>\n  )\n}\n```\n\n#### useOtpListener Hook\n\n```typescript\nimport React from 'react'\nimport { Button, Text, View } from 'react-native'\nimport { useOtpListener } from '@avasapp/react-native-otp-autofill'\n\nconst SmsVerificationComponent = () => {\n  const {\n    isListening,\n    loading,\n    receivedOtp,\n    receivedMessage,\n    error,\n    startListener,\n    stopListener,\n  } = useOtpListener({\n    onOtpReceived: (otp, message) => {\n      console.log('OTP received:', otp)\n      console.log('Full message:', message)\n      // Process the OTP\n    },\n    onTimeout: (message) => {\n      console.log('SMS timeout:', message)\n    },\n    onError: (error, code) => {\n      console.error('SMS error:', error, 'Code:', code)\n    },\n  })\n\n  return (\n    <View>\n      <Button\n        title={\n          loading\n            ? 'Starting...'\n            : isListening\n            ? 'Listening...'\n            : 'Start SMS Listener'\n        }\n        onPress={startListener}\n        disabled={isListening || loading}\n      />\n\n      <Button title=\"Stop Listener\" onPress={stopListener} disabled={!isListening} />\n\n      {receivedOtp ? <Text>OTP: {receivedOtp}</Text> : null}\n      {error ? <Text>Error: {error}</Text> : null}\n    </View>\n  )\n}\n```\n\n#### Complete Example with Both Hooks\n\n```typescript\nimport React, { useState } from 'react'\nimport { Button, Text, TextInput, View } from 'react-native'\nimport { useGetHash, useOtpListener } from '@avasapp/react-native-otp-autofill'\n\nconst SmsVerificationFlow = () => {\n  const [step, setStep] = useState<'hash' | 'sms' | 'complete'>('hash')\n  const [phoneNumber, setPhoneNumber] = useState('')\n\n  // Get app hash first\n  const {\n    hash,\n    loading: hashLoading,\n    error: hashError,\n  } = useGetHash({\n    onSuccess: (hash) => {\n      console.log('Ready to send SMS with hash:', hash)\n      setStep('sms')\n    },\n  })\n\n  // Listen for SMS\n  const { isListening, receivedOtp, startListener, stopListener } =\n    useOtpListener({\n      onOtpReceived: (otp) => {\n        console.log('Verification complete:', otp)\n        setStep('complete')\n        stopListener()\n      },\n    })\n\n  const sendSms = async () => {\n    if (!hash) return\n\n    // Send SMS with your backend API\n    await fetch('/api/send-sms', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({\n        phoneNumber,\n        appHash: hash,\n      }),\n    })\n\n    // Start listening for SMS\n    startListener()\n  }\n\n  if (step === 'hash') {\n    return (\n      <View>\n        <Text>Preparing SMS verification...</Text>\n        {hashLoading ? <Text>Loading...</Text> : null}\n        {hashError ? <Text>Error: {hashError.message}</Text> : null}\n        {hash ? <Text>Ready! Hash: {hash}</Text> : null}\n      </View>\n    )\n  }\n\n  if (step === 'sms') {\n    return (\n      <View>\n        <TextInput\n          keyboardType=\"phone-pad\"\n          placeholder=\"Phone number\"\n          value={phoneNumber}\n          onChangeText={setPhoneNumber}\n        />\n        <Button title=\"Send SMS\" onPress={sendSms} disabled={!phoneNumber} />\n        {isListening ? <Text>Waiting for SMS...</Text> : null}\n      </View>\n    )\n  }\n\n  return (\n    <View>\n      <Text>✅ Verification complete!</Text>\n      <Text>OTP: {receivedOtp}</Text>\n    </View>\n  )\n}\n```\n\n### Manual API (no hooks)\n\nIf you prefer direct control without hooks, use the module methods and event listeners:\n\n```typescript\nimport { AvasOtpAutofillModule } from '@avasapp/react-native-otp-autofill'\n\n// Get app signature hash (use the first one)\nconst getAppHash = async (): Promise<string | undefined> => {\n  try {\n    const hashes = await AvasOtpAutofillModule.getHash()\n    console.log('App signature hashes:', hashes)\n    return hashes[0]\n  } catch (error) {\n    console.error('Error getting app hash:', error)\n  }\n}\n\n// Start listening for SMS and wire up events\nconst startSmsListener = async () => {\n  const subs = [] as import('expo-modules-core').EventSubscription[]\n\n  subs.push(\n    AvasOtpAutofillModule.addListener('onSmsReceived', ({ otp, message }) => {\n      console.log('OTP received:', otp)\n      console.log('Full message:', message)\n      // ...verify with your backend\n    }),\n  )\n\n  subs.push(\n    AvasOtpAutofillModule.addListener('onTimeout', ({ message }) => {\n      console.log('SMS timeout:', message)\n    }),\n  )\n\n  subs.push(\n    AvasOtpAutofillModule.addListener('onError', ({ message, code }) => {\n      console.error('SMS error:', message, 'code:', code)\n    }),\n  )\n\n  await AvasOtpAutofillModule.startOtpListener()\n\n  // Return a cleanup function\n  return () => {\n    subs.forEach((s) => s.remove())\n    AvasOtpAutofillModule.stopSmsRetriever()\n  }\n}\n```\n\n#### Manual example (React component)\n\n```tsx\nimport React, { useRef, useState } from 'react'\nimport { Button, Text, View } from 'react-native'\nimport { AvasOtpAutofillModule } from '@avasapp/react-native-otp-autofill'\n\nexport const ManualSmsVerification = () => {\n  const [otp, setOtp] = useState<string | null>(null)\n  const [message, setMessage] = useState<string | null>(null)\n  const [isListening, setIsListening] = useState(false)\n  const cleanupRef = useRef<null | (() => void)>(null)\n\n  const start = async () => {\n    if (isListening) return\n    setIsListening(true)\n    setOtp(null)\n    setMessage(null)\n\n    // Register listeners first\n    const subs = [\n      AvasOtpAutofillModule.addListener('onSmsReceived', ({ otp, message }) => {\n        setOtp(otp ?? null)\n        setMessage(message)\n        setIsListening(false)\n        cleanup()\n      }),\n      AvasOtpAutofillModule.addListener('onTimeout', () => {\n        setIsListening(false)\n        cleanup()\n      }),\n      AvasOtpAutofillModule.addListener('onError', () => {\n        setIsListening(false)\n        cleanup()\n      }),\n    ]\n\n    const cleanup = () => {\n      subs.forEach((s) => s.remove())\n      AvasOtpAutofillModule.stopSmsRetriever()\n      cleanupRef.current = null\n    }\n\n    cleanupRef.current = cleanup\n    await AvasOtpAutofillModule.startOtpListener()\n  }\n\n  const stop = () => {\n    cleanupRef.current?.()\n    setIsListening(false)\n  }\n\n  return (\n    <View>\n      <Button title={isListening ? 'Listening…' : 'Start SMS Listener'} onPress={start} disabled={isListening} />\n      {isListening ? <Button title=\"Stop\" onPress={stop} /> : null}\n      {otp ? <Text>OTP: {otp}</Text> : null}\n      {message ? <Text>Message: {message}</Text> : null}\n    </View>\n  )\n}\n```\n\n## API Reference\n\n### React Hooks\n\n#### `useGetHash(options?: UseGetHashOptions): UseGetHashReturn`\n\nA React hook for managing app signature hash retrieval with automatic loading states and error handling.\n\n**Options:**\n\n```typescript\ninterface UseGetHashOptions {\n  onSuccess?: (value: string) => void\n  onError?: (error: Error) => void\n}\n```\n\n**Returns:**\n\n```typescript\ninterface UseGetHashReturn {\n  hash: string | null // The app signature hash\n  loading: boolean // Whether hash is being fetched\n  error: Error | null // Any error that occurred\n  refetch: () => Promise<void> // Function to refetch the hash\n}\n```\n\n**Example:**\n\n```typescript\nconst { hash, loading, error, refetch } = useGetHash({\n  onSuccess: (hash) => console.log('Hash:', hash),\n  onError: (error) => console.error('Error:', error),\n})\n```\n\n#### `useOtpListener(options?: UseOtpListenerOptions): UseOtpListenerReturn`\n\nA React hook for managing SMS OTP listening with automatic cleanup and state management.\n\n**Options:**\n\n```typescript\ninterface UseOtpListenerOptions {\n  onOtpReceived?: (otp: string, message: string) => void\n  onTimeout?: (message: string) => void\n  onError?: (error: string, code: number) => void\n}\n```\n\n**Returns:**\n\n```typescript\ninterface UseOtpListenerReturn {\n  isListening: boolean // Whether actively listening for SMS\n  loading: boolean // Whether starting/stopping listener\n  receivedOtp: string | null // Last received OTP\n  receivedMessage: string | null // Full SMS message\n  error: string | null // Any error message\n  startListener: () => Promise<void> // Start listening for SMS\n  stopListener: () => void // Stop listening and cleanup\n}\n```\n\n**Example:**\n\n```typescript\nconst { isListening, receivedOtp, startListener, stopListener } =\n  useOtpListener({\n    onOtpReceived: (otp, message) => {\n      console.log('OTP:', otp, 'Message:', message)\n    },\n  })\n```\n\n### Manual Methods\n\n#### `getHash(): Promise<string[]>`\n\nReturns the app signature hashes needed for SMS verification.\n\n```typescript\nconst hashes = await AvasOtpAutofillModule.getHash()\n```\n\n#### `startOtpListener(): Promise<boolean>`\n\nStarts listening for SMS using the Android SMS Retriever API.\n\n```typescript\nawait AvasOtpAutofillModule.startOtpListener()\n```\n\n#### `addListener(eventName, listener): EventSubscription`\n\nAdds a listener for module events. Call before `startOtpListener()`.\n\n```typescript\nconst sub = AvasOtpAutofillModule.addListener('onSmsReceived', ({ otp, message }) => {\n  console.log('OTP:', otp, 'Message:', message)\n})\n```\n\n#### Cleanup\n\nUse the returned subscription to remove listeners, and stop the retriever when done.\n\n```typescript\nsub.remove()\nawait AvasOtpAutofillModule.stopSmsRetriever()\n```\n\n### Events\n\nThe module emits the following events:\n\n- `onSmsReceived`: When an SMS is received with OTP\n- `onTimeout`: When SMS retriever times out (after 5 minutes)\n- `onError`: When an error occurs\n\nEvent payloads:\n\n```ts\ntype SmsReceivedEventPayload = {\n  message: string\n  otp: string | null\n}\n\ntype TimeoutEventPayload = {\n  message: string\n}\n\ntype ErrorEventPayload = {\n  message: string\n  code: number\n}\n```\n\n## SMS Format Requirements\n\nFor the SMS Retriever API to work, the SMS message must:\n\n1. Contain a verification code (4-6 digits)\n2. Include your app's signature hash\n3. Be no longer than 140 bytes\n4. Contain a one-time code that the user has never seen before\n\n### Example SMS Format\n\n```\nYour verification code is: 123456\n\nFA+9qCX9VSu\n```\n\nWhere `FA+9qCX9VSu` is your app's signature hash.\n\n> **Note on the app hash:** The hash is an 11-character **standard** base64 string (alphabet `A-Za-z0-9+/`, matching the provider's `^[A-Za-z0-9+/=]{11}$` pattern). It is derived from your app's signing certificate, so it differs per build variant. For builds distributed through **Play App Signing**, the hash must be derived from the **\"App signing key certificate\"** in the Play Console — this differs from your upload/debug keystore, so a hash computed locally will not match production SMS. `useGetHash` reads the runtime hash for whichever build variant is currently running, so prefer it over hardcoding a value.\n\n## Troubleshooting\n\n### Common Issues\n\n1. **SMS not received**: Ensure your SMS includes the correct app signature hash\n2. **Module not found**: Make sure the module is properly installed and linked\n3. **Timeout errors**: SMS Retriever has a 5-minute timeout limit\n4. **Hooks not updating**: Make sure you're using the hooks inside React components\n5. **Multiple listeners**: Use `stopListener()` before starting a new listener\n\n### Debug Mode\n\n#### Using Hooks for Debugging\n\n```typescript\nimport { Text, View } from 'react-native'\nimport { useGetHash, useOtpListener } from '@avasapp/react-native-otp-autofill'\n\nconst DebugComponent = () => {\n  const { hash, loading, error } = useGetHash({\n    onSuccess: (hash) => console.log('✅ Hash loaded:', hash),\n    onError: (error) => console.error('❌ Hash error:', error),\n  })\n\n  const {\n    isListening,\n    receivedOtp,\n    receivedMessage,\n    error: smsError,\n  } = useOtpListener({\n    onOtpReceived: (otp, message) => {\n      console.log('📱 SMS received:', { otp, message })\n    },\n    onTimeout: (message) => {\n      console.log('⏰ SMS timeout:', message)\n    },\n    onError: (error, code) => {\n      console.error('❌ SMS error:', { error, code })\n    },\n  })\n\n  return (\n    <View>\n      <Text>Hash: {hash || 'Loading...'}</Text>\n      <Text>Listening: {isListening ? 'Yes' : 'No'}</Text>\n      <Text>OTP: {receivedOtp || 'None'}</Text>\n      {error ? <Text>Hash Error: {error.message}</Text> : null}\n      {smsError ? <Text>SMS Error: {smsError}</Text> : null}\n    </View>\n  )\n}\n```\n\n#### Manual Event Debugging\n\n```typescript\nimport { AvasOtpAutofillModule } from '@avasapp/react-native-otp-autofill'\n\n// Listen to all events for debugging\nAvasOtpAutofillModule.addListener('onSmsReceived', (event) => {\n  console.log('📱 SMS received:', event)\n})\n\nAvasOtpAutofillModule.addListener('onTimeout', (event) => {\n  console.log('⏰ SMS timeout:', event)\n})\n\nAvasOtpAutofillModule.addListener('onError', (event) => {\n  console.log('❌ SMS error:', event)\n})\n```\n\n### Performance Tips\n\n1. **Use hooks at component level**: Don't call hooks conditionally or in loops\n2. **Clean up listeners**: Always call `stopListener()` when component unmounts\n3. **Avoid multiple hash fetches**: Use `refetch()` from `useGetHash` instead of creating new instances\n4. **Handle loading states**: Show loading indicators to improve user experience\n\n## Development\n\n### Building the Module\n\n```bash\n# Install dependencies\nbun install\n\n# Build the module\nbun run build\n\n# Clean build artifacts\nbun run clean\n\n# Run linting\nbun run lint\n\n# Run tests\nbun run test\n```\n\n### Publishing\n\nThis package is published to the npm registry. To publish a new version:\n\n1. **Update the version** in `package.json`\n2. **Build and publish**:\n   ```bash\n   bun run build\n   npm publish --access public\n   ```\n\n### Local Development\n\nFor local development and testing:\n\n```bash\n# Link the package locally\nbun link\n\n# In your test project\nbun link @avasapp/react-native-otp-autofill\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}