@hawcx/react-native-sdk 1.0.8 → 1.1.1
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/CHANGELOG.md +10 -1
- package/HawcxReactNative.podspec +2 -2
- package/README.md +325 -109
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/hawcx/reactnative/HawcxEventDispatcher.kt +4 -0
- package/android/src/main/java/com/hawcx/reactnative/HawcxReactNativeModule.kt +324 -1
- package/android/src/main/java/com/hawcx/reactnative/v6/HawcxV6Bridge.kt +402 -0
- package/ios/Frameworks/HawcxFramework.xcframework/Info.plist +5 -5
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/HawcxFramework +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Info.plist +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.abi.json +22145 -2
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.private.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/HawcxFramework +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Info.plist +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.abi.json +22145 -2
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.abi.json +22145 -2
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +628 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/_CodeSignature/CodeResources +21 -21
- package/ios/HawcxReactNative.m +56 -0
- package/ios/HawcxReactNative.swift +380 -1
- package/ios/HawcxV6BridgeSupport.swift +468 -0
- package/lib/commonjs/index.js +326 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/v6Normalization.js +325 -0
- package/lib/commonjs/v6Normalization.js.map +1 -0
- package/lib/commonjs/v6State.js +186 -0
- package/lib/commonjs/v6State.js.map +1 -0
- package/lib/commonjs/v6Types.js +2 -0
- package/lib/commonjs/v6Types.js.map +1 -0
- package/lib/commonjs/v6WebLogin.js +101 -0
- package/lib/commonjs/v6WebLogin.js.map +1 -0
- package/lib/module/index.js +287 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/v6Normalization.js +318 -0
- package/lib/module/v6Normalization.js.map +1 -0
- package/lib/module/v6State.js +173 -0
- package/lib/module/v6State.js.map +1 -0
- package/lib/module/v6Types.js +2 -0
- package/lib/module/v6Types.js.map +1 -0
- package/lib/module/v6WebLogin.js +92 -0
- package/lib/module/v6WebLogin.js.map +1 -0
- package/lib/typescript/index.d.ts +83 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/v6Normalization.d.ts +3 -0
- package/lib/typescript/v6Normalization.d.ts.map +1 -0
- package/lib/typescript/v6State.d.ts +13 -0
- package/lib/typescript/v6State.d.ts.map +1 -0
- package/lib/typescript/v6Types.d.ts +157 -0
- package/lib/typescript/v6Types.d.ts.map +1 -0
- package/lib/typescript/v6WebLogin.d.ts +32 -0
- package/lib/typescript/v6WebLogin.d.ts.map +1 -0
- package/package.json +21 -9
- package/src/index.ts +477 -0
- package/src/v6Normalization.ts +356 -0
- package/src/v6State.ts +238 -0
- package/src/v6Types.ts +194 -0
- package/src/v6WebLogin.ts +154 -0
- package/android/.settings/org.eclipse.buildship.core.prefs +0 -2
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/android/gradlew +0 -185
- package/android/gradlew.bat +0 -89
- package/android/libs/hawcx-5.1.4.aar +0 -0
- package/docs/RELEASE.md +0 -129
- package/example/README.md +0 -59
- package/example/android/app/build.gradle +0 -126
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +0 -10
- package/example/android/app/src/debug/AndroidManifest.xml +0 -9
- package/example/android/app/src/main/AndroidManifest.xml +0 -27
- package/example/android/app/src/main/java/com/hawcx/example/MainActivity.kt +0 -22
- package/example/android/app/src/main/java/com/hawcx/example/MainApplication.kt +0 -45
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -36
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +0 -3
- package/example/android/app/src/main/res/values/styles.xml +0 -9
- package/example/android/build.gradle +0 -35
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/example/android/gradle.properties +0 -41
- package/example/android/gradlew +0 -249
- package/example/android/gradlew.bat +0 -92
- package/example/android/local.properties +0 -2
- package/example/android/settings.gradle +0 -38
- package/example/app.json +0 -4
- package/example/babel.config.js +0 -3
- package/example/e2e/README.md +0 -17
- package/example/e2e/hawcx-login.yaml +0 -14
- package/example/index.js +0 -5
- package/example/ios/.xcode.env +0 -11
- package/example/ios/HawcxExampleApp/AppDelegate.h +0 -6
- package/example/ios/HawcxExampleApp/AppDelegate.mm +0 -31
- package/example/ios/HawcxExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
- package/example/ios/HawcxExampleApp/Images.xcassets/Contents.json +0 -6
- package/example/ios/HawcxExampleApp/Info.plist +0 -55
- package/example/ios/HawcxExampleApp/LaunchScreen.storyboard +0 -47
- package/example/ios/HawcxExampleApp/PrivacyInfo.xcprivacy +0 -37
- package/example/ios/HawcxExampleApp/main.m +0 -10
- package/example/ios/HawcxExampleApp.xcodeproj/project.pbxproj +0 -704
- package/example/ios/HawcxExampleApp.xcodeproj/project.xcworkspace/xcuserdata/agambhullar.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/HawcxExampleApp.xcodeproj/xcshareddata/xcschemes/HawcxExampleApp.xcscheme +0 -90
- package/example/ios/HawcxExampleApp.xcodeproj/xcuserdata/agambhullar.xcuserdatad/xcschemes/xcschememanagement.plist +0 -16
- package/example/ios/HawcxExampleApp.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/HawcxExampleAppTests/HawcxExampleAppTests.m +0 -66
- package/example/ios/HawcxExampleAppTests/Info.plist +0 -24
- package/example/ios/Podfile +0 -79
- package/example/ios/Podfile.lock +0 -1290
- package/example/metro.config.js +0 -16
- package/example/package-lock.json +0 -13220
- package/example/package.json +0 -30
- package/example/src/App.tsx +0 -755
- package/example/src/hawcx.config.ts +0 -25
- package/example/tsconfig.json +0 -8
- package/ios/Frameworks/.keep +0 -0
- package/lib/typescript/__tests__/index.test.d.ts +0 -2
- package/lib/typescript/__tests__/index.test.d.ts.map +0 -1
- package/react_mobile_sdk_plan.md +0 -242
- package/src/__tests__/index.test.ts +0 -206
package/src/index.ts
CHANGED
|
@@ -6,6 +6,55 @@ import {
|
|
|
6
6
|
NativeModule,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
9
|
+
import { normalizeV6FlowEvent } from './v6Normalization';
|
|
10
|
+
import {
|
|
11
|
+
canHawcxV6Resend,
|
|
12
|
+
createIdentifierHawcxV6AuthState,
|
|
13
|
+
createInitialHawcxV6AuthState,
|
|
14
|
+
getHawcxV6ResendAvailability,
|
|
15
|
+
normalizeHawcxV6FlowType,
|
|
16
|
+
refreshHawcxV6AuthState,
|
|
17
|
+
reduceHawcxV6FlowEvent,
|
|
18
|
+
} from './v6State';
|
|
19
|
+
import type {
|
|
20
|
+
HawcxV6AuthState,
|
|
21
|
+
HawcxV6FlowEvent,
|
|
22
|
+
HawcxV6FlowType,
|
|
23
|
+
HawcxV6StartOptions,
|
|
24
|
+
} from './v6Types';
|
|
25
|
+
import { routeWebLoginScan, type HawcxV6QrApprovalResult } from './v6WebLogin';
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
HawcxV6AwaitApprovalPrompt,
|
|
29
|
+
HawcxV6AuthState,
|
|
30
|
+
HawcxV6AuthStatus,
|
|
31
|
+
HawcxV6CompletedPayload,
|
|
32
|
+
HawcxV6EnterCodePrompt,
|
|
33
|
+
HawcxV6EnterTotpPrompt,
|
|
34
|
+
HawcxV6ErrorAction,
|
|
35
|
+
HawcxV6ErrorDetails,
|
|
36
|
+
HawcxV6ErrorPayload,
|
|
37
|
+
HawcxV6FieldError,
|
|
38
|
+
HawcxV6FlowEvent,
|
|
39
|
+
HawcxV6FlowType,
|
|
40
|
+
HawcxV6Method,
|
|
41
|
+
HawcxV6PromptPayload,
|
|
42
|
+
HawcxV6RedirectPrompt,
|
|
43
|
+
HawcxV6ResendAvailability,
|
|
44
|
+
HawcxV6RiskInfo,
|
|
45
|
+
HawcxV6RiskLocation,
|
|
46
|
+
HawcxV6SelectMethodPrompt,
|
|
47
|
+
HawcxV6SetupSmsPrompt,
|
|
48
|
+
HawcxV6SetupTotpPrompt,
|
|
49
|
+
HawcxV6StartOptions,
|
|
50
|
+
HawcxV6StepInfo,
|
|
51
|
+
} from './v6Types';
|
|
52
|
+
export type {
|
|
53
|
+
HawcxV6QrApprovalResult,
|
|
54
|
+
HawcxV6QrPayload,
|
|
55
|
+
HawcxV6QrPayloadType,
|
|
56
|
+
HawcxWebLoginScanRoute,
|
|
57
|
+
} from './v6WebLogin';
|
|
9
58
|
|
|
10
59
|
const LINKING_ERROR = [
|
|
11
60
|
"The package '@hawcx/react-native-sdk' doesn't seem to be linked.",
|
|
@@ -16,6 +65,7 @@ const LINKING_ERROR = [
|
|
|
16
65
|
const AUTH_EVENT = 'hawcx.auth.event';
|
|
17
66
|
const SESSION_EVENT = 'hawcx.session.event';
|
|
18
67
|
const PUSH_EVENT = 'hawcx.push.event';
|
|
68
|
+
const V6_FLOW_EVENT = 'hawcx.v6.flow.event';
|
|
19
69
|
|
|
20
70
|
export type HawcxInitializeConfig = {
|
|
21
71
|
projectApiKey: string;
|
|
@@ -29,6 +79,8 @@ export type HawcxInitializeConfig = {
|
|
|
29
79
|
publicKeyPem: string;
|
|
30
80
|
tokenEndpoint: string;
|
|
31
81
|
};
|
|
82
|
+
relyingParty?: string;
|
|
83
|
+
autoPollApprovals?: boolean;
|
|
32
84
|
/**
|
|
33
85
|
* @deprecated Use root-level `baseUrl` instead. Kept for backward compatibility during migration.
|
|
34
86
|
*/
|
|
@@ -86,15 +138,56 @@ export type PushEvent =
|
|
|
86
138
|
| { type: 'push_login_request'; payload: PushLoginPayload }
|
|
87
139
|
| { type: 'push_error'; payload: AuthErrorPayload };
|
|
88
140
|
|
|
141
|
+
export type HawcxV6QrApprovalOptions = {
|
|
142
|
+
rememberDevice?: boolean;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type HawcxV6AuthHookResult = {
|
|
146
|
+
state: HawcxV6AuthState;
|
|
147
|
+
start: (options: HawcxV6StartOptions) => Promise<void>;
|
|
148
|
+
selectMethod: (methodId: string) => Promise<void>;
|
|
149
|
+
submitCode: (code: string) => Promise<void>;
|
|
150
|
+
submitTotp: (code: string) => Promise<void>;
|
|
151
|
+
submitPhone: (phone: string) => Promise<void>;
|
|
152
|
+
resend: () => Promise<boolean>;
|
|
153
|
+
poll: () => Promise<void>;
|
|
154
|
+
cancel: () => Promise<void>;
|
|
155
|
+
changeIdentifier: () => Promise<void>;
|
|
156
|
+
reset: () => Promise<void>;
|
|
157
|
+
handleRedirectUrl: (url: string) => Promise<void>;
|
|
158
|
+
canResend: boolean;
|
|
159
|
+
resendAvailability: HawcxV6AuthState['resend'];
|
|
160
|
+
secondsUntilResend?: number;
|
|
161
|
+
};
|
|
162
|
+
|
|
89
163
|
type NativeBridge = {
|
|
90
164
|
initialize(config: HawcxInitializeConfig): Promise<void>;
|
|
91
165
|
authenticate(userId: string): Promise<void>;
|
|
92
166
|
submitOtp(otp: string): Promise<void>;
|
|
167
|
+
v6Start(options: HawcxV6StartOptions): Promise<void>;
|
|
168
|
+
v6SelectMethod(methodId: string): Promise<void>;
|
|
169
|
+
v6SubmitCode(code: string): Promise<void>;
|
|
170
|
+
v6SubmitTotp(code: string): Promise<void>;
|
|
171
|
+
v6SubmitPhone(phone: string): Promise<void>;
|
|
172
|
+
v6Resend(): Promise<boolean>;
|
|
173
|
+
v6Poll(): Promise<void>;
|
|
174
|
+
v6Cancel(): Promise<void>;
|
|
175
|
+
v6Reset(): Promise<void>;
|
|
176
|
+
v6ApproveQr(
|
|
177
|
+
rawPayload: string,
|
|
178
|
+
identifier: string,
|
|
179
|
+
rememberDevice: boolean,
|
|
180
|
+
): Promise<Record<string, unknown>>;
|
|
181
|
+
v6HandleRedirectUrl(url: string): Promise<void>;
|
|
93
182
|
storeBackendOAuthTokens(
|
|
94
183
|
userId: string,
|
|
95
184
|
accessToken: string,
|
|
96
185
|
refreshToken?: string | null,
|
|
97
186
|
): Promise<boolean>;
|
|
187
|
+
getLastLoggedInUser(): Promise<string>;
|
|
188
|
+
clearSessionTokens(userId: string): Promise<void>;
|
|
189
|
+
clearUserKeychainData(userId: string): Promise<void>;
|
|
190
|
+
clearLastLoggedInUser(): Promise<void>;
|
|
98
191
|
getDeviceDetails(): Promise<void>;
|
|
99
192
|
webLogin(pin: string): Promise<void>;
|
|
100
193
|
webApprove(token: string): Promise<void>;
|
|
@@ -119,6 +212,7 @@ const HawcxReactNative = HawcxReactNativeModule;
|
|
|
119
212
|
const authEventEmitter = new NativeEventEmitter(HawcxReactNativeModule);
|
|
120
213
|
const sessionEventEmitter = new NativeEventEmitter(HawcxReactNativeModule);
|
|
121
214
|
const pushEventEmitter = new NativeEventEmitter(HawcxReactNativeModule);
|
|
215
|
+
const v6FlowEventEmitter = new NativeEventEmitter(HawcxReactNativeModule);
|
|
122
216
|
|
|
123
217
|
const isIOS = () => Platform.OS === 'ios';
|
|
124
218
|
const isAndroid = () => Platform.OS === 'android';
|
|
@@ -166,6 +260,119 @@ export function submitOtp(otp: string): Promise<void> {
|
|
|
166
260
|
}
|
|
167
261
|
}
|
|
168
262
|
|
|
263
|
+
export function startV6Flow(options: HawcxV6StartOptions): Promise<void> {
|
|
264
|
+
try {
|
|
265
|
+
const identifier = ensureNonEmpty(options.identifier, 'identifier');
|
|
266
|
+
return HawcxReactNative.v6Start({
|
|
267
|
+
...options,
|
|
268
|
+
identifier,
|
|
269
|
+
flowType: normalizeHawcxV6FlowType(options.flowType),
|
|
270
|
+
startToken: options.startToken?.trim() || undefined,
|
|
271
|
+
inviteCode: options.inviteCode?.trim() || undefined,
|
|
272
|
+
codeChallenge: options.codeChallenge?.trim() || undefined,
|
|
273
|
+
});
|
|
274
|
+
} catch (error) {
|
|
275
|
+
return Promise.reject(error);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function v6SelectMethod(methodId: string): Promise<void> {
|
|
280
|
+
try {
|
|
281
|
+
return HawcxReactNative.v6SelectMethod(ensureNonEmpty(methodId, 'methodId'));
|
|
282
|
+
} catch (error) {
|
|
283
|
+
return Promise.reject(error);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function v6SubmitCode(code: string): Promise<void> {
|
|
288
|
+
try {
|
|
289
|
+
return HawcxReactNative.v6SubmitCode(ensureNonEmpty(code, 'code'));
|
|
290
|
+
} catch (error) {
|
|
291
|
+
return Promise.reject(error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function v6SubmitTotp(code: string): Promise<void> {
|
|
296
|
+
try {
|
|
297
|
+
return HawcxReactNative.v6SubmitTotp(ensureNonEmpty(code, 'code'));
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return Promise.reject(error);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function v6SubmitPhone(phone: string): Promise<void> {
|
|
304
|
+
try {
|
|
305
|
+
return HawcxReactNative.v6SubmitPhone(ensureNonEmpty(phone, 'phone'));
|
|
306
|
+
} catch (error) {
|
|
307
|
+
return Promise.reject(error);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function v6Resend(): Promise<boolean> {
|
|
312
|
+
return HawcxReactNative.v6Resend();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function v6Poll(): Promise<void> {
|
|
316
|
+
return HawcxReactNative.v6Poll();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export function v6Cancel(): Promise<void> {
|
|
320
|
+
return HawcxReactNative.v6Cancel();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export function v6Reset(): Promise<void> {
|
|
324
|
+
return HawcxReactNative.v6Reset();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const normalizeV6QrApprovalResult = (value: unknown): HawcxV6QrApprovalResult => {
|
|
328
|
+
const record =
|
|
329
|
+
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
330
|
+
? (value as Record<string, unknown>)
|
|
331
|
+
: null;
|
|
332
|
+
const outcome = record?.outcome;
|
|
333
|
+
const payloadType = record?.payloadType;
|
|
334
|
+
|
|
335
|
+
if (outcome === 'approved' && (payloadType === 'qr_auth' || payloadType === 'qr_login')) {
|
|
336
|
+
return {
|
|
337
|
+
outcome,
|
|
338
|
+
payloadType,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (outcome === 'bound' && (payloadType === 'qr_auth' || payloadType === 'qr_login')) {
|
|
343
|
+
return {
|
|
344
|
+
outcome,
|
|
345
|
+
payloadType,
|
|
346
|
+
userId: typeof record?.userId === 'string' ? record.userId : undefined,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
throw new Error('Invalid V6 QR approval response from native bridge');
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export async function approveV6Qr(
|
|
354
|
+
rawPayload: string,
|
|
355
|
+
identifier: string,
|
|
356
|
+
options: HawcxV6QrApprovalOptions = {},
|
|
357
|
+
): Promise<HawcxV6QrApprovalResult> {
|
|
358
|
+
const trimmedPayload = ensureNonEmpty(rawPayload, 'rawPayload');
|
|
359
|
+
const trimmedIdentifier = ensureNonEmpty(identifier, 'identifier');
|
|
360
|
+
const result = await HawcxReactNative.v6ApproveQr(
|
|
361
|
+
trimmedPayload,
|
|
362
|
+
trimmedIdentifier,
|
|
363
|
+
options.rememberDevice ?? false,
|
|
364
|
+
);
|
|
365
|
+
return normalizeV6QrApprovalResult(result);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function v6HandleRedirectUrl(url: string): Promise<void> {
|
|
369
|
+
try {
|
|
370
|
+
return HawcxReactNative.v6HandleRedirectUrl(ensureNonEmpty(url, 'url'));
|
|
371
|
+
} catch (error) {
|
|
372
|
+
return Promise.reject(error);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
169
376
|
export function storeBackendOAuthTokens(
|
|
170
377
|
userId: string,
|
|
171
378
|
accessToken: string,
|
|
@@ -272,10 +479,51 @@ export function addAuthListener(handler: (event: AuthEvent) => void): EmitterSub
|
|
|
272
479
|
return authEventEmitter.addListener(AUTH_EVENT, handler);
|
|
273
480
|
}
|
|
274
481
|
|
|
482
|
+
export function addV6FlowListener(handler: (event: HawcxV6FlowEvent) => void): EmitterSubscription {
|
|
483
|
+
return v6FlowEventEmitter.addListener(V6_FLOW_EVENT, (rawEvent: unknown) => {
|
|
484
|
+
const normalized = normalizeV6FlowEvent(rawEvent);
|
|
485
|
+
if (normalized) {
|
|
486
|
+
handler(normalized);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export const addHawcxV6FlowListener = addV6FlowListener;
|
|
492
|
+
export const startHawcxV6Flow = startV6Flow;
|
|
493
|
+
export const handleHawcxV6RedirectUrl = v6HandleRedirectUrl;
|
|
494
|
+
export { canHawcxV6Resend, getHawcxV6ResendAvailability };
|
|
495
|
+
export { routeWebLoginScan };
|
|
496
|
+
|
|
497
|
+
export async function getLastLoggedInUser(): Promise<string> {
|
|
498
|
+
const userId = await HawcxReactNative.getLastLoggedInUser();
|
|
499
|
+
return typeof userId === 'string' ? userId : '';
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export function logoutSession(userId: string): Promise<void> {
|
|
503
|
+
try {
|
|
504
|
+
return HawcxReactNative.clearSessionTokens(ensureNonEmpty(userId, 'userId'));
|
|
505
|
+
} catch (error) {
|
|
506
|
+
return Promise.reject(error);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export function forgetTrustedDevice(userId: string): Promise<void> {
|
|
511
|
+
try {
|
|
512
|
+
return HawcxReactNative.clearUserKeychainData(ensureNonEmpty(userId, 'userId'));
|
|
513
|
+
} catch (error) {
|
|
514
|
+
return Promise.reject(error);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export function clearLastLoggedInUser(): Promise<void> {
|
|
519
|
+
return HawcxReactNative.clearLastLoggedInUser();
|
|
520
|
+
}
|
|
521
|
+
|
|
275
522
|
export function removeAllListeners(): void {
|
|
276
523
|
authEventEmitter.removeAllListeners(AUTH_EVENT);
|
|
277
524
|
sessionEventEmitter.removeAllListeners(SESSION_EVENT);
|
|
278
525
|
pushEventEmitter.removeAllListeners(PUSH_EVENT);
|
|
526
|
+
v6FlowEventEmitter.removeAllListeners(V6_FLOW_EVENT);
|
|
279
527
|
}
|
|
280
528
|
|
|
281
529
|
export function addSessionListener(handler: (event: SessionEvent) => void): EmitterSubscription {
|
|
@@ -457,10 +705,120 @@ export class HawcxClient {
|
|
|
457
705
|
storeBackendOAuthTokens(userId: string, tokens: BackendOAuthTokens): Promise<void> {
|
|
458
706
|
return storeBackendOAuthTokens(userId, tokens.accessToken, tokens.refreshToken);
|
|
459
707
|
}
|
|
708
|
+
|
|
709
|
+
getLastLoggedInUser(): Promise<string> {
|
|
710
|
+
return getLastLoggedInUser();
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
logoutSession(userId: string): Promise<void> {
|
|
714
|
+
return logoutSession(userId);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
forgetTrustedDevice(userId: string): Promise<void> {
|
|
718
|
+
return forgetTrustedDevice(userId);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
clearLastLoggedInUser(): Promise<void> {
|
|
722
|
+
return clearLastLoggedInUser();
|
|
723
|
+
}
|
|
460
724
|
}
|
|
461
725
|
|
|
462
726
|
export const hawcxClient = new HawcxClient();
|
|
463
727
|
|
|
728
|
+
export type HawcxV6HookOptions = {
|
|
729
|
+
flowType?: HawcxV6FlowType;
|
|
730
|
+
now?: () => number;
|
|
731
|
+
resendTickMs?: number;
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
export class HawcxV6Client {
|
|
735
|
+
initialize(config: HawcxInitializeConfig): Promise<void> {
|
|
736
|
+
return initialize(config);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
start(options: HawcxV6StartOptions): Promise<void> {
|
|
740
|
+
return startV6Flow(options);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
selectMethod(methodId: string): Promise<void> {
|
|
744
|
+
return v6SelectMethod(methodId);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
submitCode(code: string): Promise<void> {
|
|
748
|
+
return v6SubmitCode(code);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
submitTotp(code: string): Promise<void> {
|
|
752
|
+
return v6SubmitTotp(code);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
submitPhone(phone: string): Promise<void> {
|
|
756
|
+
return v6SubmitPhone(phone);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
resend(): Promise<boolean> {
|
|
760
|
+
return v6Resend();
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
poll(): Promise<void> {
|
|
764
|
+
return v6Poll();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
cancel(): Promise<void> {
|
|
768
|
+
return v6Cancel();
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
reset(): Promise<void> {
|
|
772
|
+
return v6Reset();
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
approveQr(
|
|
776
|
+
rawPayload: string,
|
|
777
|
+
identifier: string,
|
|
778
|
+
options?: HawcxV6QrApprovalOptions,
|
|
779
|
+
): Promise<HawcxV6QrApprovalResult> {
|
|
780
|
+
return approveV6Qr(rawPayload, identifier, options);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
changeIdentifier(): Promise<void> {
|
|
784
|
+
return v6Reset();
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
handleRedirectUrl(url: string): Promise<void> {
|
|
788
|
+
return v6HandleRedirectUrl(url);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
addFlowListener(handler: (event: HawcxV6FlowEvent) => void): EmitterSubscription {
|
|
792
|
+
return addV6FlowListener(handler);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
storeBackendOAuthTokens(userId: string, tokens: BackendOAuthTokens): Promise<void> {
|
|
796
|
+
return storeBackendOAuthTokens(userId, tokens.accessToken, tokens.refreshToken);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
notifyUserAuthenticated(): Promise<void> {
|
|
800
|
+
return notifyUserAuthenticated();
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
getLastLoggedInUser(): Promise<string> {
|
|
804
|
+
return getLastLoggedInUser();
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
logoutSession(userId: string): Promise<void> {
|
|
808
|
+
return logoutSession(userId);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
forgetTrustedDevice(userId: string): Promise<void> {
|
|
812
|
+
return forgetTrustedDevice(userId);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
clearLastLoggedInUser(): Promise<void> {
|
|
816
|
+
return clearLastLoggedInUser();
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
export const hawcxV6Client = new HawcxV6Client();
|
|
821
|
+
|
|
464
822
|
export type HawcxAuthHookState =
|
|
465
823
|
| { status: 'idle' }
|
|
466
824
|
| { status: 'pending' }
|
|
@@ -476,6 +834,123 @@ export type HawcxWebSessionState =
|
|
|
476
834
|
| { status: 'success' }
|
|
477
835
|
| { status: 'error'; error: AuthErrorPayload };
|
|
478
836
|
|
|
837
|
+
export function useHawcxV6Auth(
|
|
838
|
+
client: HawcxV6Client = hawcxV6Client,
|
|
839
|
+
options: HawcxV6HookOptions = {},
|
|
840
|
+
): HawcxV6AuthHookResult {
|
|
841
|
+
const now = options.now ?? Date.now;
|
|
842
|
+
const resendTickMs = Math.max(250, options.resendTickMs ?? 1000);
|
|
843
|
+
const [state, setState] = useState<HawcxV6AuthState>(() =>
|
|
844
|
+
createInitialHawcxV6AuthState(options.flowType),
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
useEffect(() => {
|
|
848
|
+
const subscription = client.addFlowListener((event) => {
|
|
849
|
+
setState((previous) => reduceHawcxV6FlowEvent(event, previous, now()));
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
return () => {
|
|
853
|
+
subscription.remove();
|
|
854
|
+
};
|
|
855
|
+
}, [client, now]);
|
|
856
|
+
|
|
857
|
+
useEffect(() => {
|
|
858
|
+
if (!state.resend.resendAt || state.resend.canResend) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const intervalId = setInterval(() => {
|
|
863
|
+
setState((previous) => refreshHawcxV6AuthState(previous, now()));
|
|
864
|
+
}, resendTickMs);
|
|
865
|
+
|
|
866
|
+
return () => {
|
|
867
|
+
clearInterval(intervalId);
|
|
868
|
+
};
|
|
869
|
+
}, [now, resendTickMs, state.resend.canResend, state.resend.resendAt]);
|
|
870
|
+
|
|
871
|
+
const start = useCallback(
|
|
872
|
+
(startOptions: HawcxV6StartOptions) => {
|
|
873
|
+
const identifier = ensureNonEmpty(startOptions.identifier, 'identifier');
|
|
874
|
+
const flowType = normalizeHawcxV6FlowType(startOptions.flowType ?? options.flowType);
|
|
875
|
+
|
|
876
|
+
setState((previous) =>
|
|
877
|
+
createIdentifierHawcxV6AuthState({
|
|
878
|
+
previous,
|
|
879
|
+
identifier,
|
|
880
|
+
flowType,
|
|
881
|
+
}),
|
|
882
|
+
);
|
|
883
|
+
|
|
884
|
+
return client.start({
|
|
885
|
+
...startOptions,
|
|
886
|
+
identifier,
|
|
887
|
+
flowType,
|
|
888
|
+
});
|
|
889
|
+
},
|
|
890
|
+
[client, options.flowType],
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
const selectMethod = useCallback((methodId: string) => client.selectMethod(methodId), [client]);
|
|
894
|
+
|
|
895
|
+
const submitCode = useCallback((code: string) => client.submitCode(code), [client]);
|
|
896
|
+
|
|
897
|
+
const submitTotp = useCallback((code: string) => client.submitTotp(code), [client]);
|
|
898
|
+
|
|
899
|
+
const submitPhone = useCallback((phone: string) => client.submitPhone(phone), [client]);
|
|
900
|
+
|
|
901
|
+
const resend = useCallback(() => client.resend(), [client]);
|
|
902
|
+
const poll = useCallback(() => client.poll(), [client]);
|
|
903
|
+
|
|
904
|
+
const cancel = useCallback(async () => {
|
|
905
|
+
await client.cancel();
|
|
906
|
+
setState((previous) =>
|
|
907
|
+
createIdentifierHawcxV6AuthState({
|
|
908
|
+
previous,
|
|
909
|
+
identifier: previous.identifier,
|
|
910
|
+
}),
|
|
911
|
+
);
|
|
912
|
+
}, [client]);
|
|
913
|
+
|
|
914
|
+
const reset = useCallback(async () => {
|
|
915
|
+
await client.reset();
|
|
916
|
+
setState((previous) =>
|
|
917
|
+
createIdentifierHawcxV6AuthState({
|
|
918
|
+
previous,
|
|
919
|
+
identifier: previous.identifier,
|
|
920
|
+
}),
|
|
921
|
+
);
|
|
922
|
+
}, [client]);
|
|
923
|
+
|
|
924
|
+
const changeIdentifier = useCallback(async () => {
|
|
925
|
+
await client.changeIdentifier();
|
|
926
|
+
setState((previous) =>
|
|
927
|
+
createIdentifierHawcxV6AuthState({
|
|
928
|
+
previous,
|
|
929
|
+
}),
|
|
930
|
+
);
|
|
931
|
+
}, [client]);
|
|
932
|
+
|
|
933
|
+
const handleRedirectUrl = useCallback((url: string) => client.handleRedirectUrl(url), [client]);
|
|
934
|
+
|
|
935
|
+
return {
|
|
936
|
+
state,
|
|
937
|
+
start,
|
|
938
|
+
selectMethod,
|
|
939
|
+
submitCode,
|
|
940
|
+
submitTotp,
|
|
941
|
+
submitPhone,
|
|
942
|
+
resend,
|
|
943
|
+
poll,
|
|
944
|
+
cancel,
|
|
945
|
+
changeIdentifier,
|
|
946
|
+
reset,
|
|
947
|
+
handleRedirectUrl,
|
|
948
|
+
canResend: state.resend.canResend,
|
|
949
|
+
resendAvailability: state.resend,
|
|
950
|
+
secondsUntilResend: state.resend.secondsUntilResend,
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
479
954
|
export function useHawcxAuth(client: HawcxClient = hawcxClient) {
|
|
480
955
|
const [state, setState] = useState<HawcxAuthHookState>({ status: 'idle' });
|
|
481
956
|
const otpAttempts = useRef(0);
|
|
@@ -547,9 +1022,11 @@ export const __INTERNAL_EVENTS__ = {
|
|
|
547
1022
|
authEmitter: authEventEmitter,
|
|
548
1023
|
sessionEmitter: sessionEventEmitter,
|
|
549
1024
|
pushEmitter: pushEventEmitter,
|
|
1025
|
+
v6FlowEmitter: v6FlowEventEmitter,
|
|
550
1026
|
authEventName: AUTH_EVENT,
|
|
551
1027
|
sessionEventName: SESSION_EVENT,
|
|
552
1028
|
pushEventName: PUSH_EVENT,
|
|
1029
|
+
v6FlowEventName: V6_FLOW_EVENT,
|
|
553
1030
|
};
|
|
554
1031
|
|
|
555
1032
|
export function useHawcxWebLogin(client: HawcxClient = hawcxClient) {
|