UNPKG

capacitor-biometric-authentication

Version:

Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!

1 lines 82.1 kB
{"version":3,"file":"plugin.mjs","sources":["esm/core/types.js","esm/core/platform-detector.js","esm/core/BiometricAuthCore.js","esm/adapters/WebAdapter.js","esm/adapters/CapacitorAdapter.js","esm/index.js","esm/adapters/ReactNativeAdapter.js","esm/adapters/ElectronAdapter.js"],"sourcesContent":["export var BiometricErrorCode;\n(function (BiometricErrorCode) {\n BiometricErrorCode[\"BIOMETRIC_UNAVAILABLE\"] = \"BIOMETRIC_UNAVAILABLE\";\n BiometricErrorCode[\"AUTHENTICATION_FAILED\"] = \"AUTHENTICATION_FAILED\";\n BiometricErrorCode[\"USER_CANCELLED\"] = \"USER_CANCELLED\";\n BiometricErrorCode[\"TIMEOUT\"] = \"TIMEOUT\";\n BiometricErrorCode[\"LOCKOUT\"] = \"LOCKOUT\";\n BiometricErrorCode[\"NOT_ENROLLED\"] = \"NOT_ENROLLED\";\n BiometricErrorCode[\"PLATFORM_NOT_SUPPORTED\"] = \"PLATFORM_NOT_SUPPORTED\";\n BiometricErrorCode[\"UNKNOWN_ERROR\"] = \"UNKNOWN_ERROR\";\n})(BiometricErrorCode || (BiometricErrorCode = {}));\nexport var BiometryType;\n(function (BiometryType) {\n BiometryType[\"FINGERPRINT\"] = \"fingerprint\";\n BiometryType[\"FACE_ID\"] = \"faceId\";\n BiometryType[\"TOUCH_ID\"] = \"touchId\";\n BiometryType[\"IRIS\"] = \"iris\";\n BiometryType[\"MULTIPLE\"] = \"multiple\";\n BiometryType[\"UNKNOWN\"] = \"unknown\";\n})(BiometryType || (BiometryType = {}));\n//# sourceMappingURL=types.js.map","export class PlatformDetector {\n constructor() {\n this.platformInfo = null;\n }\n static getInstance() {\n if (!PlatformDetector.instance) {\n PlatformDetector.instance = new PlatformDetector();\n }\n return PlatformDetector.instance;\n }\n detect() {\n var _a, _b;\n if (this.platformInfo) {\n return this.platformInfo;\n }\n const info = {\n name: 'unknown',\n isCapacitor: false,\n isReactNative: false,\n isCordova: false,\n isWeb: false,\n isIOS: false,\n isAndroid: false,\n isElectron: false\n };\n // Check if we're in a browser environment\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n info.isWeb = true;\n // Check for Capacitor\n if (window.Capacitor) {\n info.isCapacitor = true;\n const capacitor = window.Capacitor;\n const platform = (_a = capacitor === null || capacitor === void 0 ? void 0 : capacitor.getPlatform) === null || _a === void 0 ? void 0 : _a.call(capacitor);\n if (platform) {\n info.name = platform;\n info.isIOS = platform === 'ios';\n info.isAndroid = platform === 'android';\n info.isWeb = platform === 'web';\n }\n }\n // Check for Cordova\n else if (window.cordova || window.phonegap) {\n info.isCordova = true;\n info.name = 'cordova';\n const userAgent = navigator.userAgent || navigator.vendor || window.opera || '';\n if (/android/i.test(userAgent)) {\n info.isAndroid = true;\n info.name = 'android';\n }\n else if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {\n info.isIOS = true;\n info.name = 'ios';\n }\n }\n // Check for Electron\n else if (((_b = window.process) === null || _b === void 0 ? void 0 : _b.type) === 'renderer' || navigator.userAgent.indexOf('Electron') !== -1) {\n info.isElectron = true;\n info.name = 'electron';\n }\n // Default to web\n else {\n info.name = 'web';\n }\n }\n // Check for React Native\n else if (typeof global !== 'undefined' && global.nativePerformanceNow) {\n info.isReactNative = true;\n info.name = 'react-native';\n // Try to detect platform in React Native\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any\n const { Platform } = require('react-native');\n if (Platform) {\n info.name = Platform.OS;\n info.isIOS = Platform.OS === 'ios';\n info.isAndroid = Platform.OS === 'android';\n }\n }\n catch (_c) {\n // React Native not available\n }\n }\n // Node.js environment\n else if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n info.name = 'node';\n }\n // Get version info if available\n if (info.isCapacitor && typeof window !== 'undefined') {\n const capacitor = window.Capacitor;\n if (capacitor === null || capacitor === void 0 ? void 0 : capacitor.version) {\n info.version = capacitor.version;\n }\n }\n else if (info.isReactNative) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any\n const { Platform } = require('react-native');\n info.version = Platform.Version;\n }\n catch (_d) {\n // Ignore\n }\n }\n this.platformInfo = info;\n return info;\n }\n isSupported() {\n const info = this.detect();\n return info.isWeb || info.isCapacitor || info.isReactNative || info.isCordova;\n }\n getPlatformName() {\n return this.detect().name;\n }\n isNativePlatform() {\n const info = this.detect();\n return (info.isIOS || info.isAndroid) && (info.isCapacitor || info.isReactNative || info.isCordova);\n }\n}\n//# sourceMappingURL=platform-detector.js.map","import { BiometricErrorCode } from './types';\nimport { PlatformDetector } from './platform-detector';\nexport class BiometricAuthCore {\n constructor() {\n this.config = {\n adapter: 'auto',\n debug: false,\n sessionDuration: 300000, // 5 minutes\n };\n this.adapters = new Map();\n this.currentAdapter = null;\n this.state = {\n isAuthenticated: false\n };\n this.platformDetector = PlatformDetector.getInstance();\n this.subscribers = new Set();\n this.initialize();\n }\n static getInstance() {\n if (!BiometricAuthCore.instance) {\n BiometricAuthCore.instance = new BiometricAuthCore();\n }\n return BiometricAuthCore.instance;\n }\n async initialize() {\n // Detect platform and load appropriate adapter\n const platformInfo = this.platformDetector.detect();\n if (this.config.debug) {\n console.warn('[BiometricAuth] Platform detected:', platformInfo);\n }\n // Load adapter based on platform\n await this.loadAdapter(platformInfo.name);\n }\n async loadAdapter(platform) {\n var _a;\n try {\n // Try custom adapters first\n if ((_a = this.config.customAdapters) === null || _a === void 0 ? void 0 : _a[platform]) {\n this.currentAdapter = this.config.customAdapters[platform];\n return;\n }\n // Try to load from registered adapters\n if (this.adapters.has(platform)) {\n this.currentAdapter = this.adapters.get(platform);\n return;\n }\n // Dynamic import based on platform\n switch (platform) {\n case 'web':\n const { WebAdapter } = await import('../adapters/WebAdapter');\n this.currentAdapter = new WebAdapter();\n break;\n case 'ios':\n case 'android':\n // Check if Capacitor is available\n if (this.platformDetector.detect().isCapacitor) {\n const { CapacitorAdapter } = await import('../adapters/CapacitorAdapter');\n this.currentAdapter = new CapacitorAdapter();\n }\n else if (this.platformDetector.detect().isReactNative) {\n // Dynamic import for React Native\n try {\n const { ReactNativeAdapter } = await import('../adapters/ReactNativeAdapter');\n this.currentAdapter = new ReactNativeAdapter();\n }\n catch (_b) {\n throw new Error('React Native biometric module not installed. Please install react-native-biometrics');\n }\n }\n break;\n case 'electron':\n const { ElectronAdapter } = await import('../adapters/ElectronAdapter');\n this.currentAdapter = new ElectronAdapter();\n break;\n default:\n throw new Error(`Platform ${platform} not supported`);\n }\n }\n catch (error) {\n if (this.config.debug) {\n console.warn('[BiometricAuth] Failed to load adapter:', error);\n }\n // Fallback to web adapter if available\n if (platform !== 'web' && this.platformDetector.detect().isWeb) {\n const { WebAdapter } = await import('../adapters/WebAdapter');\n this.currentAdapter = new WebAdapter();\n }\n }\n }\n configure(config) {\n this.config = Object.assign(Object.assign({}, this.config), config);\n // Re-initialize if adapter changed\n if (config.adapter && config.adapter !== 'auto') {\n this.loadAdapter(config.adapter);\n }\n }\n registerAdapter(name, adapter) {\n this.adapters.set(name, adapter);\n }\n async isAvailable() {\n if (!this.currentAdapter) {\n return false;\n }\n try {\n return await this.currentAdapter.isAvailable();\n }\n catch (error) {\n if (this.config.debug) {\n console.warn('[BiometricAuth] isAvailable error:', error);\n }\n return false;\n }\n }\n async getSupportedBiometrics() {\n if (!this.currentAdapter) {\n return [];\n }\n try {\n return await this.currentAdapter.getSupportedBiometrics();\n }\n catch (error) {\n if (this.config.debug) {\n console.warn('[BiometricAuth] getSupportedBiometrics error:', error);\n }\n return [];\n }\n }\n async authenticate(options) {\n if (!this.currentAdapter) {\n return {\n success: false,\n error: {\n code: BiometricErrorCode.PLATFORM_NOT_SUPPORTED,\n message: 'No biometric adapter available for this platform'\n }\n };\n }\n try {\n const result = await this.currentAdapter.authenticate(options);\n if (result.success) {\n this.updateState({\n isAuthenticated: true,\n sessionId: result.sessionId,\n lastAuthTime: Date.now(),\n biometryType: result.biometryType,\n error: undefined\n });\n // Set up session timeout\n if (this.config.sessionDuration && this.config.sessionDuration > 0) {\n setTimeout(() => {\n this.logout();\n }, this.config.sessionDuration);\n }\n }\n else {\n this.updateState({\n isAuthenticated: false,\n error: result.error\n });\n }\n return result;\n }\n catch (error) {\n const errorResult = {\n success: false,\n error: {\n code: BiometricErrorCode.UNKNOWN_ERROR,\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n details: error\n }\n };\n this.updateState({\n isAuthenticated: false,\n error: errorResult.error\n });\n return errorResult;\n }\n }\n async deleteCredentials() {\n if (!this.currentAdapter) {\n throw new Error('No biometric adapter available');\n }\n await this.currentAdapter.deleteCredentials();\n this.logout();\n }\n async hasCredentials() {\n if (!this.currentAdapter) {\n return false;\n }\n try {\n return await this.currentAdapter.hasCredentials();\n }\n catch (error) {\n if (this.config.debug) {\n console.warn('[BiometricAuth] hasCredentials error:', error);\n }\n return false;\n }\n }\n logout() {\n this.updateState({\n isAuthenticated: false,\n sessionId: undefined,\n lastAuthTime: undefined,\n biometryType: undefined,\n error: undefined\n });\n }\n getState() {\n return Object.assign({}, this.state);\n }\n isAuthenticated() {\n if (!this.state.isAuthenticated || !this.state.lastAuthTime) {\n return false;\n }\n // Check if session is still valid\n if (this.config.sessionDuration && this.config.sessionDuration > 0) {\n const elapsed = Date.now() - this.state.lastAuthTime;\n if (this.config.sessionDuration && elapsed > this.config.sessionDuration) {\n this.logout();\n return false;\n }\n }\n return true;\n }\n subscribe(callback) {\n this.subscribers.add(callback);\n // Return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n };\n }\n updateState(newState) {\n this.state = Object.assign(Object.assign({}, this.state), newState);\n // Notify subscribers\n this.subscribers.forEach(callback => {\n callback(this.getState());\n });\n }\n // Utility methods for common use cases\n async requireAuthentication(callback, options) {\n var _a;\n if (!this.isAuthenticated()) {\n const result = await this.authenticate(options);\n if (!result.success) {\n throw new Error(((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || 'Authentication failed');\n }\n }\n return callback();\n }\n async withAuthentication(callback, options) {\n var _a;\n if (!this.isAuthenticated()) {\n const result = await this.authenticate(options);\n if (!result.success) {\n throw new Error(((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || 'Authentication failed');\n }\n }\n return callback();\n }\n}\n//# sourceMappingURL=BiometricAuthCore.js.map","import { BiometricErrorCode, BiometryType } from '../core/types';\nexport class WebAdapter {\n constructor() {\n this.platform = 'web';\n this.credentials = new Map();\n // Set default Relying Party info\n this.rpId = window.location.hostname;\n this.rpName = document.title || 'Biometric Authentication';\n }\n async isAvailable() {\n // Check if WebAuthn is supported\n if (!window.PublicKeyCredential) {\n return false;\n }\n // Check if platform authenticator is available\n try {\n const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n return available;\n }\n catch (_a) {\n return false;\n }\n }\n async getSupportedBiometrics() {\n if (!(await this.isAvailable())) {\n return [];\n }\n // WebAuthn doesn't provide specific biometry types\n // Return generic \"multiple\" as modern devices support various methods\n return [BiometryType.MULTIPLE];\n }\n async authenticate(options) {\n var _a;\n try {\n // Check if WebAuthn is available\n if (!(await this.isAvailable())) {\n return {\n success: false,\n error: {\n code: BiometricErrorCode.BIOMETRIC_UNAVAILABLE,\n message: 'WebAuthn is not available on this device'\n }\n };\n }\n const webOptions = ((_a = options === null || options === void 0 ? void 0 : options.platform) === null || _a === void 0 ? void 0 : _a.web) || {};\n // Try to get existing credential first\n const existingCredential = await this.getExistingCredential(webOptions);\n if (existingCredential) {\n return {\n success: true,\n biometryType: BiometryType.MULTIPLE,\n sessionId: this.generateSessionId(),\n platform: 'web'\n };\n }\n // If no existing credential, create a new one\n const credential = await this.createCredential((options === null || options === void 0 ? void 0 : options.reason) || 'Authentication required', webOptions);\n if (credential) {\n // Store credential for future use\n const credentialId = this.arrayBufferToBase64(credential.rawId);\n this.credentials.set(credentialId, credential);\n this.saveCredentialId(credentialId);\n return {\n success: true,\n biometryType: BiometryType.MULTIPLE,\n sessionId: this.generateSessionId(),\n platform: 'web'\n };\n }\n return {\n success: false,\n error: {\n code: BiometricErrorCode.AUTHENTICATION_FAILED,\n message: 'Failed to authenticate'\n }\n };\n }\n catch (error) {\n return this.handleError(error);\n }\n }\n async deleteCredentials() {\n this.credentials.clear();\n localStorage.removeItem('biometric_credential_ids');\n }\n async hasCredentials() {\n const storedIds = this.getStoredCredentialIds();\n return storedIds.length > 0;\n }\n async getExistingCredential(options) {\n const storedIds = this.getStoredCredentialIds();\n if (storedIds.length === 0) {\n return null;\n }\n try {\n const challenge = options.challenge || crypto.getRandomValues(new Uint8Array(32));\n const publicKeyOptions = {\n challenge,\n rpId: options.rpId || this.rpId,\n timeout: options.timeout || 60000,\n userVerification: options.userVerification || 'preferred',\n allowCredentials: storedIds.map(id => ({\n id: this.base64ToArrayBuffer(id),\n type: 'public-key'\n }))\n };\n const credential = await navigator.credentials.get({\n publicKey: publicKeyOptions\n });\n return credential;\n }\n catch (_a) {\n return null;\n }\n }\n async createCredential(_reason, options) {\n try {\n const challenge = options.challenge || crypto.getRandomValues(new Uint8Array(32));\n const userId = crypto.getRandomValues(new Uint8Array(32));\n const publicKeyOptions = {\n challenge,\n rp: {\n id: options.rpId || this.rpId,\n name: options.rpName || this.rpName\n },\n user: {\n id: userId,\n name: 'user@' + this.rpId,\n displayName: 'User'\n },\n pubKeyCredParams: [\n { type: 'public-key', alg: -7 }, // ES256\n { type: 'public-key', alg: -257 } // RS256\n ],\n authenticatorSelection: options.authenticatorSelection || {\n authenticatorAttachment: 'platform',\n userVerification: 'preferred',\n requireResidentKey: false,\n residentKey: 'discouraged'\n },\n timeout: options.timeout || 60000,\n attestation: options.attestation || 'none'\n };\n const credential = await navigator.credentials.create({\n publicKey: publicKeyOptions\n });\n return credential;\n }\n catch (_a) {\n return null;\n }\n }\n handleError(error) {\n let code = BiometricErrorCode.UNKNOWN_ERROR;\n let message = 'An unknown error occurred';\n if (error instanceof DOMException) {\n switch (error.name) {\n case 'NotAllowedError':\n code = BiometricErrorCode.USER_CANCELLED;\n message = 'User cancelled the authentication';\n break;\n case 'AbortError':\n code = BiometricErrorCode.USER_CANCELLED;\n message = 'Authentication was aborted';\n break;\n case 'SecurityError':\n code = BiometricErrorCode.AUTHENTICATION_FAILED;\n message = 'Security error during authentication';\n break;\n case 'InvalidStateError':\n code = BiometricErrorCode.AUTHENTICATION_FAILED;\n message = 'Invalid state for authentication';\n break;\n case 'NotSupportedError':\n code = BiometricErrorCode.BIOMETRIC_UNAVAILABLE;\n message = 'WebAuthn is not supported';\n break;\n default:\n message = error.message || message;\n }\n }\n else if (error instanceof Error) {\n message = error.message;\n }\n return {\n success: false,\n error: {\n code,\n message,\n details: error\n }\n };\n }\n generateSessionId() {\n return Array.from(crypto.getRandomValues(new Uint8Array(16)))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n }\n arrayBufferToBase64(buffer) {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n base64ToArrayBuffer(base64) {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n }\n getStoredCredentialIds() {\n const stored = localStorage.getItem('biometric_credential_ids');\n if (!stored) {\n return [];\n }\n try {\n return JSON.parse(stored);\n }\n catch (_a) {\n return [];\n }\n }\n saveCredentialId(id) {\n const existing = this.getStoredCredentialIds();\n if (!existing.includes(id)) {\n existing.push(id);\n localStorage.setItem('biometric_credential_ids', JSON.stringify(existing));\n }\n }\n}\n//# sourceMappingURL=WebAdapter.js.map","import { BiometricErrorCode, BiometryType } from '../core/types';\nexport class CapacitorAdapter {\n constructor() {\n this.platform = 'capacitor';\n // Plugin will be loaded dynamically\n }\n async getPlugin() {\n if (this.capacitorPlugin) {\n return this.capacitorPlugin;\n }\n try {\n // Try to get the registered Capacitor plugin\n const capacitorCore = await import('@capacitor/core');\n // Try using registerPlugin if available\n if (capacitorCore.registerPlugin) {\n try {\n this.capacitorPlugin = capacitorCore.registerPlugin('BiometricAuth');\n if (this.capacitorPlugin) {\n return this.capacitorPlugin;\n }\n }\n catch (_a) {\n // Continue to fallback\n }\n }\n // Legacy support for older Capacitor versions\n const legacyPlugins = capacitorCore.Plugins;\n if (legacyPlugins === null || legacyPlugins === void 0 ? void 0 : legacyPlugins.BiometricAuth) {\n this.capacitorPlugin = legacyPlugins.BiometricAuth;\n return this.capacitorPlugin;\n }\n // If not found in Plugins, try direct import\n // This allows the plugin to work even if not properly registered\n const BiometricAuthPlugin = window.BiometricAuthPlugin;\n if (BiometricAuthPlugin) {\n this.capacitorPlugin = BiometricAuthPlugin;\n return this.capacitorPlugin;\n }\n throw new Error('BiometricAuth Capacitor plugin not found');\n }\n catch (error) {\n throw new Error('Failed to load Capacitor plugin: ' + error.message);\n }\n }\n async isAvailable() {\n try {\n const plugin = await this.getPlugin();\n const result = await plugin.isAvailable();\n return result.isAvailable || false;\n }\n catch (_a) {\n return false;\n }\n }\n async getSupportedBiometrics() {\n try {\n const plugin = await this.getPlugin();\n const result = await plugin.getSupportedBiometrics();\n // Map Capacitor biometry types to our types\n return (result.biometryTypes || []).map((type) => {\n switch (type.toLowerCase()) {\n case 'fingerprint':\n return BiometryType.FINGERPRINT;\n case 'faceid':\n case 'face_id':\n return BiometryType.FACE_ID;\n case 'touchid':\n case 'touch_id':\n return BiometryType.TOUCH_ID;\n case 'iris':\n return BiometryType.IRIS;\n default:\n return BiometryType.UNKNOWN;\n }\n }).filter((type) => type !== BiometryType.UNKNOWN);\n }\n catch (_a) {\n return [];\n }\n }\n async authenticate(options) {\n var _a, _b;\n try {\n const plugin = await this.getPlugin();\n // Map our options to Capacitor plugin options\n const capacitorOptions = Object.assign(Object.assign({ reason: (options === null || options === void 0 ? void 0 : options.reason) || 'Authenticate to continue', cancelTitle: options === null || options === void 0 ? void 0 : options.cancelTitle, fallbackTitle: options === null || options === void 0 ? void 0 : options.fallbackTitle, disableDeviceCredential: options === null || options === void 0 ? void 0 : options.disableDeviceCredential, maxAttempts: options === null || options === void 0 ? void 0 : options.maxAttempts, requireConfirmation: options === null || options === void 0 ? void 0 : options.requireConfirmation }, (((_a = options === null || options === void 0 ? void 0 : options.platform) === null || _a === void 0 ? void 0 : _a.android) || {})), (((_b = options === null || options === void 0 ? void 0 : options.platform) === null || _b === void 0 ? void 0 : _b.ios) || {}));\n const result = await plugin.authenticate(capacitorOptions);\n if (result.success) {\n const biometryType = this.mapBiometryType(result.biometryType);\n return {\n success: true,\n biometryType,\n sessionId: this.generateSessionId(),\n platform: 'capacitor'\n };\n }\n else {\n return {\n success: false,\n error: this.mapError(result.error)\n };\n }\n }\n catch (error) {\n return {\n success: false,\n error: this.mapError(error)\n };\n }\n }\n async deleteCredentials() {\n try {\n const plugin = await this.getPlugin();\n await plugin.deleteCredentials();\n }\n catch (_a) {\n // Ignore errors when deleting credentials\n }\n }\n async hasCredentials() {\n try {\n const plugin = await this.getPlugin();\n // Check if the plugin has a hasCredentials method\n if (typeof plugin.hasCredentials === 'function') {\n const result = await plugin.hasCredentials();\n return result.hasCredentials || false;\n }\n // Fallback: assume credentials exist if biometrics are available\n return await this.isAvailable();\n }\n catch (_a) {\n return false;\n }\n }\n mapBiometryType(type) {\n if (!type) {\n return BiometryType.UNKNOWN;\n }\n switch (type.toLowerCase()) {\n case 'fingerprint':\n return BiometryType.FINGERPRINT;\n case 'faceid':\n case 'face_id':\n return BiometryType.FACE_ID;\n case 'touchid':\n case 'touch_id':\n return BiometryType.TOUCH_ID;\n case 'iris':\n return BiometryType.IRIS;\n default:\n return BiometryType.UNKNOWN;\n }\n }\n mapError(error) {\n let code = BiometricErrorCode.UNKNOWN_ERROR;\n let message = 'An unknown error occurred';\n const errorObj = error;\n if (errorObj === null || errorObj === void 0 ? void 0 : errorObj.code) {\n switch (errorObj.code) {\n case 'BIOMETRIC_UNAVAILABLE':\n case 'UNAVAILABLE':\n code = BiometricErrorCode.BIOMETRIC_UNAVAILABLE;\n message = errorObj.message || 'Biometric authentication is not available';\n break;\n case 'USER_CANCELLED':\n case 'CANCELLED':\n case 'USER_CANCEL':\n code = BiometricErrorCode.USER_CANCELLED;\n message = errorObj.message || 'User cancelled authentication';\n break;\n case 'AUTHENTICATION_FAILED':\n case 'FAILED':\n code = BiometricErrorCode.AUTHENTICATION_FAILED;\n message = errorObj.message || 'Authentication failed';\n break;\n case 'TIMEOUT':\n code = BiometricErrorCode.TIMEOUT;\n message = errorObj.message || 'Authentication timed out';\n break;\n case 'LOCKOUT':\n code = BiometricErrorCode.LOCKOUT;\n message = errorObj.message || 'Too many failed attempts';\n break;\n case 'NOT_ENROLLED':\n code = BiometricErrorCode.NOT_ENROLLED;\n message = errorObj.message || 'No biometric credentials enrolled';\n break;\n default:\n message = errorObj.message || message;\n }\n }\n else if (error instanceof Error) {\n message = error.message;\n }\n else if (typeof error === 'string') {\n message = error;\n }\n return {\n code,\n message,\n details: error\n };\n }\n generateSessionId() {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n }\n}\n//# sourceMappingURL=CapacitorAdapter.js.map","var _a;\nimport { BiometricAuthCore } from './core/BiometricAuthCore';\n// Create singleton instance\nconst biometricAuth = BiometricAuthCore.getInstance();\n// Export the main API (provider-less, like Zustand)\nconst BiometricAuth = {\n // Core methods\n configure: (config) => biometricAuth.configure(config),\n isAvailable: () => biometricAuth.isAvailable(),\n getSupportedBiometrics: () => biometricAuth.getSupportedBiometrics(),\n authenticate: (options) => biometricAuth.authenticate(options),\n deleteCredentials: () => biometricAuth.deleteCredentials(),\n hasCredentials: () => biometricAuth.hasCredentials(),\n // State management\n logout: () => biometricAuth.logout(),\n getState: () => biometricAuth.getState(),\n isAuthenticated: () => biometricAuth.isAuthenticated(),\n subscribe: (callback) => biometricAuth.subscribe(callback),\n // Utility methods\n requireAuthentication: (callback, options) => biometricAuth.requireAuthentication(callback, options),\n withAuthentication: (callback, options) => biometricAuth.withAuthentication(callback, options),\n // Advanced usage\n registerAdapter: (name, adapter) => biometricAuth.registerAdapter(name, adapter),\n};\nexport { BiometricErrorCode } from './core/types';\n// Export the main API as default\nexport default BiometricAuth;\n// Also export named for flexibility\nexport { BiometricAuth };\n// Export core classes for advanced usage\nexport { BiometricAuthCore } from './core/BiometricAuthCore';\nexport { PlatformDetector } from './core/platform-detector';\n// Export adapters for those who want to use them directly\nexport { WebAdapter } from './adapters/WebAdapter';\nexport { CapacitorAdapter } from './adapters/CapacitorAdapter';\n// For backward compatibility with Capacitor plugin registration\nif (typeof window !== 'undefined') {\n const capacitorGlobal = window;\n if ((_a = capacitorGlobal.Capacitor) === null || _a === void 0 ? void 0 : _a.registerPlugin) {\n // Register as a Capacitor plugin for backward compatibility\n const { registerPlugin } = capacitorGlobal.Capacitor;\n if (registerPlugin) {\n try {\n // Create a Capacitor-compatible plugin interface\n const BiometricAuthPlugin = {\n isAvailable: async () => ({ isAvailable: await BiometricAuth.isAvailable() }),\n getSupportedBiometrics: async () => ({\n biometryTypes: await BiometricAuth.getSupportedBiometrics()\n }),\n authenticate: async (options) => {\n const result = await BiometricAuth.authenticate(options);\n return {\n success: result.success,\n error: result.error,\n biometryType: result.biometryType\n };\n },\n deleteCredentials: async () => {\n await BiometricAuth.deleteCredentials();\n return {};\n }\n };\n // Register the plugin\n registerPlugin('BiometricAuth', {\n web: BiometricAuthPlugin\n });\n }\n catch (_b) {\n // Ignore registration errors - not critical\n }\n }\n }\n}\n//# sourceMappingURL=index.js.map","import { BiometricErrorCode, BiometryType } from '../core/types';\nexport class ReactNativeAdapter {\n constructor() {\n this.platform = 'react-native';\n // Biometrics module will be loaded dynamically\n }\n async getBiometrics() {\n if (this.biometrics) {\n return this.biometrics;\n }\n try {\n // Dynamic import for React Native biometrics\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any\n const ReactNativeBiometrics = require('react-native-biometrics').default;\n this.biometrics = new ReactNativeBiometrics();\n return this.biometrics;\n }\n catch (_a) {\n throw new Error('React Native Biometrics not installed. Please run: npm install react-native-biometrics');\n }\n }\n async isAvailable() {\n try {\n const biometrics = await this.getBiometrics();\n const { available } = await biometrics.isSensorAvailable();\n return available;\n }\n catch (_a) {\n return false;\n }\n }\n async getSupportedBiometrics() {\n try {\n const biometrics = await this.getBiometrics();\n const { available, biometryType } = await biometrics.isSensorAvailable();\n if (!available) {\n return [];\n }\n // Map React Native biometry types to our types\n switch (biometryType) {\n case 'TouchID':\n return [BiometryType.TOUCH_ID];\n case 'FaceID':\n return [BiometryType.FACE_ID];\n case 'Biometrics':\n case 'Fingerprint':\n return [BiometryType.FINGERPRINT];\n default:\n return [BiometryType.UNKNOWN];\n }\n }\n catch (_a) {\n return [];\n }\n }\n async authenticate(options) {\n try {\n const biometrics = await this.getBiometrics();\n // Check if biometrics are available\n const { available, biometryType, error } = await biometrics.isSensorAvailable();\n if (!available) {\n return {\n success: false,\n error: {\n code: BiometricErrorCode.BIOMETRIC_UNAVAILABLE,\n message: error || 'Biometric authentication is not available'\n }\n };\n }\n // Create signature for authentication\n const { success, signature, error: authError } = await biometrics.createSignature({\n promptMessage: (options === null || options === void 0 ? void 0 : options.reason) || 'Authenticate',\n cancelButtonText: (options === null || options === void 0 ? void 0 : options.cancelTitle) || 'Cancel',\n payload: 'biometric-auth-payload'\n });\n if (success && signature) {\n return {\n success: true,\n biometryType: this.mapBiometryType(biometryType),\n sessionId: this.generateSessionId(),\n platform: 'react-native'\n };\n }\n else {\n return {\n success: false,\n error: this.mapError(authError)\n };\n }\n }\n catch (error) {\n return {\n success: false,\n error: this.mapError(error)\n };\n }\n }\n async deleteCredentials() {\n try {\n const biometrics = await this.getBiometrics();\n await biometrics.deleteKeys();\n }\n catch (_a) {\n // Ignore errors when deleting credentials\n }\n }\n async hasCredentials() {\n try {\n const biometrics = await this.getBiometrics();\n const { keysExist } = await biometrics.biometricKeysExist();\n return keysExist;\n }\n catch (_a) {\n return false;\n }\n }\n mapBiometryType(type) {\n if (!type) {\n return BiometryType.UNKNOWN;\n }\n switch (type) {\n case 'TouchID':\n return BiometryType.TOUCH_ID;\n case 'FaceID':\n return BiometryType.FACE_ID;\n case 'Biometrics':\n case 'Fingerprint':\n return BiometryType.FINGERPRINT;\n default:\n return BiometryType.UNKNOWN;\n }\n }\n mapError(error) {\n let code = BiometricErrorCode.UNKNOWN_ERROR;\n let message = 'An unknown error occurred';\n if (typeof error === 'string') {\n message = error;\n // Map common error messages to error codes\n if (error.includes('cancelled') || error.includes('canceled')) {\n code = BiometricErrorCode.USER_CANCELLED;\n }\n else if (error.includes('failed') || error.includes('not recognized')) {\n code = BiometricErrorCode.AUTHENTICATION_FAILED;\n }\n else if (error.includes('locked')) {\n code = BiometricErrorCode.LOCKOUT;\n }\n }\n else if (error instanceof Error) {\n message = error.message;\n }\n return {\n code,\n message,\n details: error\n };\n }\n generateSessionId() {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n }\n}\n//# sourceMappingURL=ReactNativeAdapter.js.map","import { BiometricErrorCode, BiometryType } from '../core/types';\nexport class ElectronAdapter {\n constructor() {\n this.platform = 'electron';\n // Electron-specific initialization\n }\n async isAvailable() {\n try {\n // Check if we're in Electron main or renderer process\n if (typeof process !== 'undefined' && process.versions && process.versions.electron) {\n // In Electron, we can use TouchID on macOS\n if (process.platform === 'darwin') {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const electronModule = require('electron');\n const { systemPreferences } = electronModule.remote || electronModule;\n return systemPreferences.canPromptTouchID();\n }\n // Windows Hello support could be added here\n return false;\n }\n return false;\n }\n catch (_a) {\n return false;\n }\n }\n async getSupportedBiometrics() {\n if (!(await this.isAvailable())) {\n return [];\n }\n // On macOS, we support Touch ID\n if (process.platform === 'darwin') {\n return [BiometryType.TOUCH_ID];\n }\n return [];\n }\n async authenticate(options) {\n try {\n if (!(await this.isAvailable())) {\n return {\n success: false,\n error: {\n code: BiometricErrorCode.BIOMETRIC_UNAVAILABLE,\n message: 'Biometric authentication is not available'\n }\n };\n }\n if (process.platform === 'darwin') {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const electronModule = require('electron');\n const { systemPreferences } = electronModule.remote || electronModule;\n try {\n await systemPreferences.promptTouchID((options === null || options === void 0 ? void 0 : options.reason) || 'authenticate with Touch ID');\n return {\n success: true,\n biometryType: BiometryType.TOUCH_ID,\n sessionId: this.generateSessionId(),\n platform: 'electron'\n };\n }\n catch (_a) {\n return {\n success: false,\n error: {\n code: BiometricErrorCode.AUTHENTICATION_FAILED,\n message: 'Touch ID authentication failed'\n }\n };\n }\n }\n return {\n success: false,\n error: {\n code: BiometricErrorCode.PLATFORM_NOT_SUPPORTED,\n message: 'Platform not supported'\n }\n };\n }\n catch (error) {\n return {\n success: false,\n error: this.mapError(error)\n };\n }\n }\n async deleteCredentials() {\n // Electron doesn't store biometric credentials\n // This is a no-op\n }\n async hasCredentials() {\n // In Electron, we don't store credentials\n // Return true if biometrics are available\n return await this.isAvailable();\n }\n mapError(error) {\n let code = BiometricErrorCode.UNKNOWN_ERROR;\n let message = 'An unknown error occurred';\n if (error instanceof Error) {\n message = error.message;\n if (message.includes('cancelled') || message.includes('canceled')) {\n code = BiometricErrorCode.USER_CANCELLED;\n }\n else if (message.includes('failed')) {\n code = BiometricErrorCode.AUTHENTICATION_FAILED;\n }\n }\n return {\n code,\n message,\n details: error\n };\n }\n generateSessionId() {\n return Date.now().toString(36) + Math.random().toString(36).substr(2);\n }\n}\n//# sourceMappingURL=ElectronAdapter.js.map"],"names":[],"mappings":"AAAU,IAAC;AACX,CAAC,UAAU,kBAAkB,EAAE;AAC/B,IAAI,kBAAkB,CAAC,uBAAuB,CAAC,GAAG,uBAAuB;AACzE,IAAI,kBAAkB,CAAC,uBAAuB,CAAC,GAAG,uBAAuB;AACzE,IAAI,kBAAkB,CAAC,gBAAgB,CAAC,GAAG,gBAAgB;AAC3D,IAAI,kBAAkB,CAAC,SAAS,CAAC,GAAG,SAAS;AAC7C,IAAI,kBAAkB,CAAC,SAAS,CAAC,GAAG,SAAS;AAC7C,IAAI,kBAAkB,CAAC,cAAc,CAAC,GAAG,cAAc;AACvD,IAAI,kBAAkB,CAAC,wBAAwB,CAAC,GAAG,wBAAwB;AAC3E,IAAI,kBAAkB,CAAC,eAAe,CAAC,GAAG,eAAe;AACzD,CAAC,EAAE,kBAAkB,KAAK,kBAAkB,GAAG,EAAE,CAAC,CAAC;AAC5C,IAAI,YAAY;AACvB,CAAC,UAAU,YAAY,EAAE;AACzB,IAAI,YAAY,CAAC,aAAa,CAAC,GAAG,aAAa;AAC/C,IAAI,YAAY,CAAC,SAAS,CAAC,GAAG,QAAQ;AACtC,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,SAAS;AACxC,IAAI,YAAY,CAAC,MAAM,CAAC,GAAG,MAAM;AACjC,IAAI,YAAY,CAAC,UAAU,CAAC,GAAG,UAAU;AACzC,IAAI,YAAY,CAAC,SAAS,CAAC,GAAG,SAAS;AACvC,CAAC,EAAE,YAAY,KAAK,YAAY,GAAG,EAAE,CAAC,CAAC;;ACnBhC,MAAM,gBAAgB,CAAC;AAC9B,IAAI,WAAW,GAAG;AAClB,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;AAChC,IAAI;AACJ,IAAI,OAAO,WAAW,GAAG;AACzB,QAAQ,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE;AACxC,YAAY,gBAAgB,CAAC,QAAQ,GAAG,IAAI,gBAAgB,EAAE;AAC9D,QAAQ;AACR,QAAQ,OAAO,gBAAgB,CAAC,QAAQ;AACxC,IAAI;AACJ,IAAI,MAAM,GAAG;AACb,QAAQ,IAAI,EAAE,EAAE,EAAE;AAClB,QAAQ,IAAI,IAAI,CAAC,YAAY,EAAE;AAC/B,YAAY,OAAO,IAAI,CAAC,YAAY;AACpC,QAAQ;AACR,QAAQ,MAAM,IAAI,GAAG;AACrB,YAAY,IAAI,EAAE,SAAS;AAC3B,YAAY,WAAW,EAAE,KAAK;AAC9B,YAAY,aAAa,EAAE,KAAK;AAChC,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,KAAK,EAAE,KAAK;AACxB,YAAY,KAAK,EAAE,KAAK;AACxB,YAAY,SAAS,EAAE,KAAK;AAC5B,YAAY,UAAU,EAAE;AACxB,SAAS;AACT;AACA,QAAQ,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE;AAC9E,YAAY,IAAI,CAAC,KAAK,GAAG,IAAI;AAC7B;AACA,YAAY,IAAI,MAAM,CAAC,SAAS,EAAE;AAClC,gBAAgB,IAAI,CAAC,WAAW,GAAG,IAAI;AACvC,gBAAgB,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS;AAClD,gBAAgB,MAAM,QAAQ,GAAG,CAAC,EAAE,GAAG,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;AAC3K,gBAAgB,IAAI,QAAQ,EAAE;AAC9B,oBAAoB,IAAI,CAAC,IAAI,GAAG,QAAQ;AACxC,oBAAoB,IAAI,CAAC,KAAK,GAAG,QAAQ,KAAK,KAAK;AACnD,oBAAoB,IAAI,CAAC,SAAS,GAAG,QAAQ,KAAK,SAAS;AAC3D,oBAAoB,IAAI,CAAC,KAAK,GAAG,QAAQ,KAAK,KAAK;AACnD,gBAAgB;AAChB,YAAY;AACZ;AACA,iBAAiB,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE;AACxD,gBAAgB,IAAI,CAAC,SAAS,GAAG,IAAI;AACrC,gBAAgB,IAAI,CAAC,IAAI,GAAG,SAAS;AACrC,gBAAgB,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,IAAI,EAAE;AAC/F,gBAAgB,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAChD,oBAAoB,IAAI,CAAC,SAAS,GAAG,IAAI;AACzC,oBAAoB,IAAI,CAAC,IAAI,GAAG,SAAS;AACzC,gBAAgB;AAChB,qBAAqB,IAAI,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AACjF,oBAAoB,IAAI,CAAC,KAAK,GAAG,IAAI;AACrC,oBAAoB,IAAI,CAAC,IAAI,GAAG,KAAK;AACrC,gBAAgB;AAChB,YAAY;AACZ;AACA,iBAAiB,IAAI,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,IAAI,MAAM,UAAU,IAAI,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE;AAC5J,gBAAgB,IAAI,CAAC,UAAU,GAAG,IAAI;AACtC,gBAAgB,IAAI,CAAC,IAAI,GAAG,UAAU;AACtC,YAAY;AACZ;AACA,iBAAiB;AACjB,gBAAgB,IAAI,CAAC,IAAI,GAAG,KAAK;AACjC,YAAY;AACZ,QAAQ;AACR;AACA,aAAa,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,oBAAoB,EAAE;AAC/E