react-native-otp-auto-verify 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +467 -452
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/otpautoverify/OtpAutoVerifyModule.kt +148 -153
- package/lib/module/NativeOtpAutoVerify.ts +18 -6
- package/lib/module/index.js +48 -17
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeOtpAutoVerify.d.ts +3 -3
- package/lib/typescript/src/NativeOtpAutoVerify.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +19 -11
- package/src/NativeOtpAutoVerify.ts +18 -6
- package/src/index.tsx +54 -24
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
NativeModules,
|
|
3
|
+
TurboModuleRegistry,
|
|
4
|
+
type TurboModule,
|
|
5
|
+
} from 'react-native';
|
|
2
6
|
|
|
3
|
-
export interface
|
|
7
|
+
export interface Spec extends TurboModule {
|
|
4
8
|
getConstants(): { OTP_RECEIVED_EVENT: string };
|
|
5
9
|
getHash(): Promise<ReadonlyArray<string>>;
|
|
6
10
|
startSmsRetriever(): Promise<boolean>;
|
|
@@ -8,9 +12,9 @@ export interface OtpAutoVerifySpec extends TurboModule {
|
|
|
8
12
|
removeListeners(count: number): void;
|
|
9
13
|
}
|
|
10
14
|
|
|
11
|
-
function
|
|
15
|
+
function loadNativeModule(): Spec {
|
|
12
16
|
try {
|
|
13
|
-
return TurboModuleRegistry.getEnforcing<
|
|
17
|
+
return TurboModuleRegistry.getEnforcing<Spec>('OtpAutoVerify');
|
|
14
18
|
} catch {
|
|
15
19
|
const legacy = NativeModules.OtpAutoVerify;
|
|
16
20
|
if (!legacy) {
|
|
@@ -18,8 +22,16 @@ function getNativeModule(): OtpAutoVerifySpec {
|
|
|
18
22
|
'OtpAutoVerify native module is not available. Ensure the library is properly linked.'
|
|
19
23
|
);
|
|
20
24
|
}
|
|
21
|
-
return legacy as
|
|
25
|
+
return legacy as Spec;
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
let cachedModule: Spec | null = null;
|
|
30
|
+
|
|
31
|
+
/** Resolves the native module on first use so importing this package does not throw before APIs run. */
|
|
32
|
+
export function getOtpNativeModule(): Spec {
|
|
33
|
+
if (cachedModule === null) {
|
|
34
|
+
cachedModule = loadNativeModule();
|
|
35
|
+
}
|
|
36
|
+
return cachedModule;
|
|
37
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { NativeEventEmitter, Platform } from 'react-native';
|
|
3
|
-
import
|
|
3
|
+
import { getOtpNativeModule } from './NativeOtpAutoVerify';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
? new NativeEventEmitter(NativeOtpAutoVerify)
|
|
8
|
-
: null;
|
|
9
|
-
|
|
10
|
-
const OTP_RECEIVED_EVENT =
|
|
11
|
-
(NativeOtpAutoVerify.getConstants?.()?.OTP_RECEIVED_EVENT as string) ??
|
|
12
|
-
'otpReceived';
|
|
5
|
+
/** Must match native `OTP_RECEIVED_EVENT` (Android/iOS). */
|
|
6
|
+
export const OTP_RECEIVED_EVENT = 'otpReceived';
|
|
13
7
|
|
|
14
8
|
export const TIMEOUT_MESSAGE = 'Timeout Error.';
|
|
15
9
|
const DEFAULT_DIGITS = 6;
|
|
@@ -19,11 +13,29 @@ const MAX_OTP_DIGITS = 8;
|
|
|
19
13
|
|
|
20
14
|
export type OtpDigits = 4 | 5 | 6 | 7 | 8;
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
let androidEventEmitter: NativeEventEmitter | null | undefined;
|
|
17
|
+
|
|
18
|
+
function getAndroidEventEmitter(): NativeEventEmitter | null {
|
|
19
|
+
if (Platform.OS !== 'android') return null;
|
|
20
|
+
if (androidEventEmitter !== undefined) {
|
|
21
|
+
return androidEventEmitter;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
androidEventEmitter = new NativeEventEmitter(getOtpNativeModule());
|
|
25
|
+
return androidEventEmitter;
|
|
26
|
+
} catch {
|
|
27
|
+
androidEventEmitter = null;
|
|
28
|
+
return null;
|
|
25
29
|
}
|
|
26
|
-
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getOtpRegex(digits: number): RegExp {
|
|
33
|
+
const d =
|
|
34
|
+
digits >= MIN_OTP_DIGITS && digits <= MAX_OTP_DIGITS
|
|
35
|
+
? digits
|
|
36
|
+
: DEFAULT_DIGITS;
|
|
37
|
+
// Prefer non-`\b` boundaries so OTPs still match after ":" and similar (e.g. "OTP:123456").
|
|
38
|
+
return new RegExp(`(^|[^0-9])(\\d{${d}})(?!\\d)`);
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
export interface UseOtpVerificationOptions {
|
|
@@ -64,13 +76,13 @@ export function extractOtp(
|
|
|
64
76
|
if (!trimmed) return null;
|
|
65
77
|
const regex = getOtpRegex(numberOfDigits);
|
|
66
78
|
const match = trimmed.match(regex);
|
|
67
|
-
return match ? match[
|
|
79
|
+
return match ? match[2]! : null;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
/** Returns app hash strings for the current app. Android only; iOS returns []. */
|
|
71
83
|
export async function getHash(): Promise<string[]> {
|
|
72
84
|
if (Platform.OS !== 'android') return [];
|
|
73
|
-
const arr = await
|
|
85
|
+
const arr = await getOtpNativeModule().getHash();
|
|
74
86
|
return Array.from(arr);
|
|
75
87
|
}
|
|
76
88
|
|
|
@@ -84,12 +96,17 @@ export async function activateOtpListener(
|
|
|
84
96
|
handler: (sms: string, extractedOtp?: string | null) => void,
|
|
85
97
|
options?: { numberOfDigits?: OtpDigits }
|
|
86
98
|
): Promise<OtpListenerSubscription> {
|
|
87
|
-
if (Platform.OS !== 'android'
|
|
99
|
+
if (Platform.OS !== 'android') {
|
|
100
|
+
return NOOP_SUBSCRIPTION;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const emitter = getAndroidEventEmitter();
|
|
104
|
+
if (!emitter) {
|
|
88
105
|
return NOOP_SUBSCRIPTION;
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
const numberOfDigits = options?.numberOfDigits ?? DEFAULT_DIGITS;
|
|
92
|
-
const subscription =
|
|
109
|
+
const subscription = emitter.addListener(
|
|
93
110
|
OTP_RECEIVED_EVENT,
|
|
94
111
|
(...args: unknown[]) => {
|
|
95
112
|
const smsText = String(args[0] ?? '');
|
|
@@ -97,11 +114,21 @@ export async function activateOtpListener(
|
|
|
97
114
|
}
|
|
98
115
|
);
|
|
99
116
|
|
|
100
|
-
|
|
117
|
+
try {
|
|
118
|
+
await getOtpNativeModule().startSmsRetriever();
|
|
119
|
+
} catch (err) {
|
|
120
|
+
subscription.remove();
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
|
|
101
124
|
return {
|
|
102
125
|
remove: () => {
|
|
103
126
|
subscription.remove();
|
|
104
|
-
|
|
127
|
+
try {
|
|
128
|
+
getOtpNativeModule().removeListeners(0);
|
|
129
|
+
} catch {
|
|
130
|
+
// Native may be unavailable during teardown
|
|
131
|
+
}
|
|
105
132
|
},
|
|
106
133
|
};
|
|
107
134
|
}
|
|
@@ -111,8 +138,11 @@ export async function activateOtpListener(
|
|
|
111
138
|
* The native module ignores the count parameter and always unregisters the SMS receiver.
|
|
112
139
|
*/
|
|
113
140
|
export function removeListener(): void {
|
|
114
|
-
if (Platform.OS
|
|
115
|
-
|
|
141
|
+
if (Platform.OS !== 'android') return;
|
|
142
|
+
try {
|
|
143
|
+
getOtpNativeModule().removeListeners(0);
|
|
144
|
+
} catch {
|
|
145
|
+
// Native not linked or already torn down
|
|
116
146
|
}
|
|
117
147
|
}
|
|
118
148
|
|
|
@@ -153,7 +183,9 @@ export function useOtpVerification(
|
|
|
153
183
|
const hashes = await getHash();
|
|
154
184
|
setHashCode(hashes[0] ?? '');
|
|
155
185
|
} catch (err) {
|
|
156
|
-
|
|
186
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
187
|
+
setError(wrapped);
|
|
188
|
+
return;
|
|
157
189
|
}
|
|
158
190
|
|
|
159
191
|
const sub = await activateOtpListener(
|
|
@@ -193,5 +225,3 @@ export function useOtpVerification(
|
|
|
193
225
|
[hashCode, otp, sms, timeoutError, error, startListening, stopListening]
|
|
194
226
|
);
|
|
195
227
|
}
|
|
196
|
-
|
|
197
|
-
export { OTP_RECEIVED_EVENT };
|