{"_id":"@blusalt-sdk/react-native-blusalt-mno-liveness","name":"@blusalt-sdk/react-native-blusalt-mno-liveness","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@blusalt-sdk/react-native-blusalt-mno-liveness","version":"1.0.0","description":"MNO verification library","main":"./lib/module/index.js","types":"./lib/typescript/src/index.d.ts","exports":{".":{"react-native-blusalt-mno-liveness-source":"./src/index.tsx","types":"./lib/typescript/src/index.d.ts","default":"./lib/module/index.js"},"./package.json":"./package.json"},"scripts":{"example":"yarn workspace react-native-blusalt-mno-liveness-example","clean":"del-cli android/build example/android/build example/android/app/build example/ios/build lib","prepare":"bob build","typecheck":"tsc","lint":"eslint \"**/*.{js,ts,tsx}\"","test":"jest","release":"release-it --only-version","web":"vite","build:web":"vite build"},"keywords":["react-native","ios","android"],"repository":{"type":"git","url":"git+https://github.com/Blusalt-FS/React-native-MNO-Liveness.git.git"},"author":{"name":"Folarin","email":"folarin@blusalt.net","url":"https://blusalt.net"},"license":"MIT","bugs":{"url":"https://github.com/Blusalt-FS/React-native-MNO-Liveness.git/issues"},"homepage":"https://github.com/Blusalt-FS/React-native-MNO-Liveness.git#readme","publishConfig":{"registry":"https://registry.npmjs.org/"},"devDependencies":{"@commitlint/config-conventional":"^21.0.2","@eslint/compat":"^2.1.0","@eslint/eslintrc":"^3.3.5","@eslint/js":"^10.0.1","@jest/globals":"^29.7.0","@react-native-community/cli":"20.1.0","@react-native/babel-preset":"0.85.0","@react-native/eslint-config":"0.85.0","@react-native/jest-preset":"0.85.0","@release-it/conventional-changelog":"^11.0.1","@types/react":"^19.2.0","commitlint":"^21.0.2","del-cli":"^7.0.0","eslint":"^9.39.4","eslint-config-prettier":"^10.1.8","eslint-plugin-ft-flow":"^3.0.11","eslint-plugin-prettier":"^5.5.6","jest":"^29.7.0","lefthook":"^2.1.9","prettier":"^3.8.3","react":"19.2.3","react-native":"0.85.0","react-native-builder-bob":"^0.41.0","react-native-web":"~0.21.2","release-it":"^20.2.0","turbo":"^2.9.16","typescript":"^6.0.3"},"peerDependencies":{"react":"*","react-native":"*"},"workspaces":["example"],"packageManager":"yarn@4.11.0","react-native-builder-bob":{"source":"src","output":"lib","targets":[["module",{"esm":true}],["typescript",{"project":"tsconfig.build.json"}]]},"codegenConfig":{"name":"BlusaltMnoLivenessSpec","type":"modules","jsSrcsDir":"src","android":{"javaPackageName":"com.surfmaxmnoliveness"}},"prettier":{"quoteProps":"consistent","singleQuote":true,"tabWidth":2,"trailingComma":"es5","useTabs":false},"jest":{"preset":"@react-native/jest-preset","testEnvironmentOptions":{"customExportConditions":["require","react-native","<%- project.sourceCondition -%>"]},"modulePathIgnorePatterns":["<rootDir>/example/node_modules","<rootDir>/lib/"]},"commitlint":{"extends":["@commitlint/config-conventional"]},"release-it":{"git":{"commitMessage":"chore: release ${version}","tagName":"v${version}"},"npm":{"publish":true},"github":{"release":true},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"create-react-native-library":{"type":"turbo-module","languages":"kotlin-objc","tools":["eslint","jest","lefthook","release-it","vite"],"version":"0.63.0"},"_id":"@blusalt-sdk/react-native-blusalt-mno-liveness@1.0.0","gitHead":"fefd67ea37b1251dd92cc361146f2cae73ae9a6d","_nodeVersion":"22.17.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-E3d8Lj4RBYVMstDXO8qmQI34xhS8s8KyGk6VLLho8GxAxaHJ5/MtB4xxmJvfjWmskBLM5CY72mOyNGMbCIOb+A==","shasum":"8bd63dae896a9eb86279f3029d9ceb43c513d678","tarball":"https://registry.npmjs.org/@blusalt-sdk/react-native-blusalt-mno-liveness/-/react-native-blusalt-mno-liveness-1.0.0.tgz","fileCount":42,"unpackedSize":39073,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDeeMN2Bqty4BHQ5G7P7HfvcbZ/1kRRObsFilwlikySiAIhAMQDNEaSC9vK0T0x9fGogFdOEEtIWrEozkaTbM6iMsG5"}]},"_npmUser":{"name":"folarinblusalt","email":"folarin@blusalt.net"},"directories":{},"maintainers":[{"name":"folarinblusalt","email":"folarin@blusalt.net"},{"name":"blusalt-fs","email":"dev@blusalt.net"},{"name":"oluwaseyiblusalt","email":"oluwaseyi@blusalt.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-blusalt-mno-liveness_1.0.0_1788281280360_0.7881390802955115"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-01T16:48:00.157Z","1.0.0":"2026-09-01T16:48:00.627Z","modified":"2026-09-01T16:48:00.888Z"},"maintainers":[{"name":"folarinblusalt","email":"folarin@blusalt.net"},{"name":"blusalt-fs","email":"dev@blusalt.net"},{"name":"oluwaseyiblusalt","email":"oluwaseyi@blusalt.net"}],"description":"MNO verification library","homepage":"https://github.com/Blusalt-FS/React-native-MNO-Liveness.git#readme","keywords":["react-native","ios","android"],"repository":{"type":"git","url":"git+https://github.com/Blusalt-FS/React-native-MNO-Liveness.git.git"},"author":{"name":"Folarin","email":"folarin@blusalt.net","url":"https://blusalt.net"},"bugs":{"url":"https://github.com/Blusalt-FS/React-native-MNO-Liveness.git/issues"},"license":"MIT","readme":"# react-native-blusalt-mno-liveness\n\nMNO Liveness Detection SDK for React Native — verify user identity with face liveness checks and facial comparison.\n\nGet your credentials from [Blusalt](https://blusalt.net/)\n\n## Features\n\n1. Face Liveness Detection — detect whether the face in front of the camera is real\n2. Facial Comparison — compare a live face against a reference image\n\n## Installation\n\n```sh\nnpm install @blusalt-sdk/react-native-blusalt-mno-liveness\n```\n\n## Usage\n\n### Liveness Detection\n\n```tsx\nimport { startLivenessDetection } from '@blusalt-sdk/react-native-blusalt-mno-liveness';\n\ntry {\n  const result = await startLivenessDetection({\n    clientId: 'your-client-id',\n    apiKey: 'your-api-key',\n    appName: 'your-app-name',\n    livenessType: 'ACTIVE',   // 'ACTIVE' | 'PASSIVE'\n    cameraType: 'FRONT',      // 'FRONT' | 'REAR'\n    isDev: false,\n    showResult: true,\n    collectDeviceId: true,\n    collectDeviceLocation: true,\n  });\n\n  console.log('Passed:', result.isProcedureValidationPassed);\n  console.log('Confidence:', result.confidencePercent);\n} catch (error: any) {\n  console.error(error.code, error.message);\n}\n```\n\n### Facial Comparison\n\n```tsx\nimport { startFacialComparison } from 'react-native-blusalt-mno-liveness';\n\ntry {\n  const result = await startFacialComparison({\n    clientId: 'your-client-id',\n    apiKey: 'your-api-key',\n    appName: 'your-app-name',\n    imageBase64: 'base64-encoded-reference-image',\n    livenessType: 'ACTIVE',\n    cameraType: 'FRONT',\n    isDev: false,\n    showResult: true,\n    thresholdPriority: 'SERVER_ONLY',\n    collectDeviceId: true,\n    collectDeviceLocation: true,\n  });\n\n  console.log('Passed:', result.isProcedureValidationPassed);\n  console.log('Comparison:', result.comparisonData?.isPassFaceComparison);\n} catch (error: any) {\n  console.error(error.code, error.message);\n}\n```\n\n## API Reference\n\n### `startLivenessDetection(options)`\n\n| Option | Type | Required | Default | Description |\n|---|---|---|---|---|\n| `clientId` | `string` | ✅ | — | Your Blusalt client ID |\n| `apiKey` | `string` | ✅ | — | Your Blusalt API key |\n| `appName` | `string` | ✅ | — | Your application name |\n| `livenessType` | `'ACTIVE' \\| 'PASSIVE'` | — | `'ACTIVE'` | Liveness check mode |\n| `cameraType` | `'FRONT' \\| 'REAR'` | — | `'FRONT'` | Camera to use |\n| `isDev` | `boolean` | — | `false` | Use sandbox environment |\n| `showResult` | `boolean` | — | `true` | Show result screen after check |\n| `startOnFirstScreen` | `boolean` | — | `false` | Auto-start on first screen |\n| `collectDeviceId` | `boolean` | — | `true` | Collect device identifier |\n| `collectDeviceLocation` | `boolean` | — | `true` | Collect device location |\n| `timeoutDuration` | `number` | — | — | Session timeout in seconds |\n\n### `startFacialComparison(options)`\n\nAll options from `startLivenessDetection`, plus:\n\n| Option | Type | Required | Default | Description |\n|---|---|---|---|---|\n| `imageBase64` | `string` | ✅ | — | Base64-encoded reference image (JPEG/PNG) |\n| `thresholdPriority` | `'SERVER_ONLY' \\| 'LOCAL_ONLY' \\| 'SERVER_WITH_LOCAL_FALLBACK'` | — | `'SERVER_ONLY'` | Matching threshold source |\n| `showScore` | `boolean` | — | — | Show match score on result screen |\n| `showThreshold` | `boolean` | — | — | Show threshold value on result screen |\n\n### Result\n\nBoth functions return a `Promise<LivenessResult>`:\n\n```ts\ninterface LivenessResult {\n  isProcedureValidationPassed: boolean;\n  confidencePercent: number;\n  thresholdPercent: number;\n  faceDetectionData?: {\n    isPassFaceGenuineness: boolean;\n    livenessImage?: string;        // base64\n    originalLivenessImage?: string; // base64\n  };\n  comparisonData?: {               // only for startFacialComparison\n    isPassFaceComparison: boolean;\n    originalImage?: string;        // base64\n  };\n}\n```\n\n---\n\n## Android Setup\n\n### Step 1 — GitHub credentials\n\nCreate `android/github.properties` in your project with your GitHub credentials.\nMake sure this file is in `.gitignore`.\n\n```properties\nUSERNAME_GITHUB=YourGitHubUsername\nTOKEN_GITHUB=YourGitHubClassicToken\n```\n\n> The token needs at least **read:packages** permission.\n\n### Step 2 — Project-level `android/build.gradle`\n\n```gradle\ndef githubPropertiesFile = rootProject.file(\"github.properties\")\ndef githubProperties = new Properties()\ngithubProperties.load(new FileInputStream(githubPropertiesFile))\n\nallprojects {\n    repositories {\n        // ... existing repos ...\n        maven {\n            name \"GitHubPackagesMNO\"\n            url 'https://maven.pkg.github.com/Blusalt-FS/MNO-Android-Package'\n            credentials {\n                username githubProperties['USERNAME_GITHUB']\n                password githubProperties['TOKEN_GITHUB']\n            }\n        }\n    }\n}\n```\n\n### Step 3 — Minimum SDK version\n\nIn `/android/app/build.gradle`:\n\n```gradle\nandroid {\n    defaultConfig {\n        minSdkVersion 24  // required\n    }\n}\n```\n\n### Step 4 — Manifest (if you see `allowBackup` merge conflict)\n\nIn `/android/app/src/main/AndroidManifest.xml`, add the `tools:replace` attribute:\n\n```xml\n<application\n    android:allowBackup=\"false\"\n    tools:replace=\"android:allowBackup\"\n    ...>\n```\n\n### Step 5 — ProGuard (release builds)\n\nIn `/android/app/proguard-rules.pro`:\n\n```proguard\n-keep class net.blusalt.liveness_native.** { *; }\n-keep class com.surfmax.** { *; }\n```\n\nEnable in `/android/app/build.gradle`:\n\n```gradle\nandroid {\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n```\n\n\nAdd below permissions as required by your app to AndroidManifest.xml\n```\n    <!-- Camera hardware features -->\n    <uses-feature\n        android:name=\"android.hardware.camera\"\n        android:required=\"false\" />\n    <uses-feature\n        android:name=\"android.hardware.camera.autofocus\"\n        android:required=\"false\" />\n    <uses-feature\n        android:glEsVersion=\"0x00020000\"\n        android:required=\"false\" />\n\n    <!-- Camera: required for liveness capture (front and rear) -->\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <!-- Network: required for SDK API calls -->\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n\n    <!-- Audio: required for liveness voice prompts -->\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\" />\n\n    <!-- Storage: required for reading/writing captured images -->\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <!-- Device metadata: required when setCollectDeviceId(true) is used -->\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n\n    <!-- Haptic feedback during liveness prompts -->\n    <uses-permission android:name=\"android.permission.VIBRATE\" />\n\n    <!-- Location: required when setCollectDeviceLocation(true) is used -->\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n```\n\n---\n\n## iOS Setup\n\nMinimum deployment target: **iOS 14**\n\n### Step 1 — Camera permission\n\nIn `ios/<YourApp>/Info.plist`:\n\n```xml\n<key>NSCameraUsageDescription</key>\n<string>Required for liveness detection</string>\n```\n\n### Step 2 — Location permission (if `collectDeviceLocation: true`)\n\n```xml\n<key>NSLocationWhenInUseUsageDescription</key>\n<string>Required to collect device location during verification</string>\n```\n\n---\n\n## Note on GitHub token\n\nIf you see an **\"Unauthorized\"** or **\"could not find\"** error during Android build, regenerate your GitHub token and ensure it has the **`read:packages`** scope. If unsure, enable all package-related scopes.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-58801f2f98d047fdc5e553663fe876bf"}