@incodetech/core 2.0.0-alpha.2 → 2.0.0-alpha.4
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/dist/OpenViduLogger-BdPfiZO6.esm.js +3 -0
- package/dist/OpenViduLogger-CQyDxBvM.esm.js +803 -0
- package/dist/{addEvent-1Mi5CEiq.esm.js → addEvent-9v4w5iO-.esm.js} +1 -1
- package/dist/email.d.ts +1 -1
- package/dist/email.esm.js +2 -2
- package/dist/{endpoints-D_pUMaqA.esm.js → endpoints-Dn1t57hJ.esm.js} +8 -3
- package/dist/flow.d.ts +3 -3
- package/dist/flow.esm.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +2 -2
- package/dist/{lib-CyIAFRfr.esm.js → lib-Bu9XGMBW.esm.js} +1 -800
- package/dist/{permissionServices-CVR0Pq38.esm.js → permissionServices-CCpxd8le.esm.js} +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/phone.esm.js +2 -2
- package/dist/selfie.d.ts +5 -4
- package/dist/selfie.esm.js +27 -10
- package/package.json +4 -1
- package/.turbo/turbo-build.log +0 -33
- package/.turbo/turbo-coverage.log +0 -22
- package/.turbo/turbo-format.log +0 -6
- package/.turbo/turbo-lint$colon$fix.log +0 -77
- package/.turbo/turbo-lint.log +0 -95
- package/.turbo/turbo-test.log +0 -870
- package/.turbo/turbo-typecheck.log +0 -5
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -221
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/camera/cameraService.ts.html +0 -580
- package/coverage/src/camera/cameraServices.ts.html +0 -163
- package/coverage/src/camera/cameraStateMachine.ts.html +0 -877
- package/coverage/src/camera/index.html +0 -146
- package/coverage/src/email/emailActor.ts.html +0 -130
- package/coverage/src/email/emailManager.ts.html +0 -1366
- package/coverage/src/email/emailStateMachine.ts.html +0 -1186
- package/coverage/src/email/index.html +0 -146
- package/coverage/src/flow/flowActor.ts.html +0 -124
- package/coverage/src/flow/flowAnalyzer.ts.html +0 -196
- package/coverage/src/flow/flowManager.ts.html +0 -790
- package/coverage/src/flow/flowServices.ts.html +0 -124
- package/coverage/src/flow/flowStateMachine.ts.html +0 -631
- package/coverage/src/flow/index.html +0 -221
- package/coverage/src/flow/moduleLoader.ts.html +0 -304
- package/coverage/src/flow/orchestratedFlowManager.ts.html +0 -778
- package/coverage/src/flow/orchestratedFlowStateMachine.ts.html +0 -1060
- package/coverage/src/http/api.ts.html +0 -355
- package/coverage/src/http/endpoints.ts.html +0 -136
- package/coverage/src/http/index.html +0 -131
- package/coverage/src/index.html +0 -116
- package/coverage/src/phone/index.html +0 -146
- package/coverage/src/phone/phoneActor.ts.html +0 -130
- package/coverage/src/phone/phoneManager.ts.html +0 -1459
- package/coverage/src/phone/phoneStateMachine.ts.html +0 -1351
- package/coverage/src/recordings/index.html +0 -116
- package/coverage/src/recordings/recordingsRepository.ts.html +0 -229
- package/coverage/src/selfie/index.html +0 -191
- package/coverage/src/selfie/selfieActor.ts.html +0 -136
- package/coverage/src/selfie/selfieErrorUtils.ts.html +0 -283
- package/coverage/src/selfie/selfieManager.ts.html +0 -988
- package/coverage/src/selfie/selfieStateMachine.ts.html +0 -2497
- package/coverage/src/selfie/selfieUploadService.ts.html +0 -328
- package/coverage/src/selfie/types.ts.html +0 -394
- package/coverage/src/setup.ts.html +0 -598
- package/src/camera/cameraActor.ts +0 -21
- package/src/camera/cameraService.test.ts +0 -437
- package/src/camera/cameraService.ts +0 -165
- package/src/camera/cameraServices.test.ts +0 -66
- package/src/camera/cameraServices.ts +0 -26
- package/src/camera/cameraStateMachine.test.ts +0 -602
- package/src/camera/cameraStateMachine.ts +0 -264
- package/src/camera/index.ts +0 -5
- package/src/camera/types.ts +0 -17
- package/src/device/getBrowser.ts +0 -31
- package/src/device/getDeviceClass.ts +0 -29
- package/src/device/index.ts +0 -2
- package/src/email/__mocks__/emailMocks.ts +0 -59
- package/src/email/emailActor.ts +0 -15
- package/src/email/emailManager.test.ts +0 -573
- package/src/email/emailManager.ts +0 -427
- package/src/email/emailServices.ts +0 -66
- package/src/email/emailStateMachine.test.ts +0 -741
- package/src/email/emailStateMachine.ts +0 -367
- package/src/email/index.ts +0 -39
- package/src/email/types.ts +0 -60
- package/src/events/addEvent.ts +0 -20
- package/src/events/types.ts +0 -7
- package/src/flow/__mocks__/flowMocks.ts +0 -84
- package/src/flow/flowActor.ts +0 -13
- package/src/flow/flowAnalyzer.test.ts +0 -266
- package/src/flow/flowAnalyzer.ts +0 -37
- package/src/flow/flowCompletionService.ts +0 -21
- package/src/flow/flowManager.test.ts +0 -560
- package/src/flow/flowManager.ts +0 -235
- package/src/flow/flowServices.test.ts +0 -109
- package/src/flow/flowServices.ts +0 -13
- package/src/flow/flowStateMachine.test.ts +0 -334
- package/src/flow/flowStateMachine.ts +0 -182
- package/src/flow/index.ts +0 -21
- package/src/flow/moduleLoader.test.ts +0 -136
- package/src/flow/moduleLoader.ts +0 -73
- package/src/flow/orchestratedFlowManager.test.ts +0 -240
- package/src/flow/orchestratedFlowManager.ts +0 -231
- package/src/flow/orchestratedFlowStateMachine.test.ts +0 -199
- package/src/flow/orchestratedFlowStateMachine.ts +0 -325
- package/src/flow/types.ts +0 -434
- package/src/http/__mocks__/api.ts +0 -88
- package/src/http/api.test.ts +0 -231
- package/src/http/api.ts +0 -90
- package/src/http/endpoints.ts +0 -17
- package/src/index.ts +0 -33
- package/src/permissions/index.ts +0 -2
- package/src/permissions/permissionServices.ts +0 -31
- package/src/permissions/types.ts +0 -3
- package/src/phone/__mocks__/phoneMocks.ts +0 -71
- package/src/phone/index.ts +0 -39
- package/src/phone/phoneActor.ts +0 -15
- package/src/phone/phoneManager.test.ts +0 -393
- package/src/phone/phoneManager.ts +0 -458
- package/src/phone/phoneServices.ts +0 -98
- package/src/phone/phoneStateMachine.test.ts +0 -918
- package/src/phone/phoneStateMachine.ts +0 -422
- package/src/phone/types.ts +0 -83
- package/src/recordings/recordingsRepository.test.ts +0 -87
- package/src/recordings/recordingsRepository.ts +0 -48
- package/src/recordings/streamingEvents.ts +0 -10
- package/src/selfie/__mocks__/selfieMocks.ts +0 -26
- package/src/selfie/index.ts +0 -14
- package/src/selfie/selfieActor.ts +0 -17
- package/src/selfie/selfieErrorUtils.test.ts +0 -116
- package/src/selfie/selfieErrorUtils.ts +0 -66
- package/src/selfie/selfieManager.test.ts +0 -297
- package/src/selfie/selfieManager.ts +0 -301
- package/src/selfie/selfieServices.ts +0 -362
- package/src/selfie/selfieStateMachine.test.ts +0 -283
- package/src/selfie/selfieStateMachine.ts +0 -804
- package/src/selfie/selfieUploadService.test.ts +0 -90
- package/src/selfie/selfieUploadService.ts +0 -81
- package/src/selfie/types.ts +0 -103
- package/src/session/index.ts +0 -5
- package/src/session/sessionService.ts +0 -78
- package/src/setup.test.ts +0 -61
- package/src/setup.ts +0 -171
- package/tsconfig.json +0 -13
- package/tsdown.config.ts +0 -22
- package/vitest.config.ts +0 -37
- package/vitest.setup.ts +0 -135
- /package/dist/{Manager-6BwbaI_H.d.ts → Manager-BGfxEmyv.d.ts} +0 -0
- /package/dist/{StateMachine-7c1gcu94.d.ts → StateMachine-DRE1oH2B.d.ts} +0 -0
- /package/dist/{types-tq1ypYSL.d.ts → types-kWlqshfM.d.ts} +0 -0
- /package/dist/{warmup-Dr7OcFND.d.ts → warmup-CEJTfxQr.d.ts} +0 -0
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module @incodetech/core/phone
|
|
3
|
-
*
|
|
4
|
-
* Phone verification module for the Incode Web SDK.
|
|
5
|
-
* Supports both headless (programmatic) and UI-driven usage patterns.
|
|
6
|
-
*
|
|
7
|
-
* ## Headless Usage
|
|
8
|
-
*
|
|
9
|
-
* The phone manager can be used entirely without UI for backend integrations,
|
|
10
|
-
* custom UI implementations, or automated workflows.
|
|
11
|
-
*
|
|
12
|
-
* @example Basic headless phone verification with OTP
|
|
13
|
-
* ```typescript
|
|
14
|
-
* import { createPhoneManager } from '@incodetech/core/phone';
|
|
15
|
-
* import { setup } from '@incodetech/core';
|
|
16
|
-
*
|
|
17
|
-
* // 1. Configure the SDK (required before using any module)
|
|
18
|
-
* setup({ apiURL: 'https://api.example.com', token: 'your-token' });
|
|
19
|
-
*
|
|
20
|
-
* // 2. Create the phone manager
|
|
21
|
-
* const phoneManager = createPhoneManager({
|
|
22
|
-
* config: {
|
|
23
|
-
* otpVerification: true,
|
|
24
|
-
* otpExpirationInMinutes: 5,
|
|
25
|
-
* prefill: false,
|
|
26
|
-
* maxOtpAttempts: 3,
|
|
27
|
-
* },
|
|
28
|
-
* });
|
|
29
|
-
*
|
|
30
|
-
* // 3. Subscribe to state changes (optional but recommended)
|
|
31
|
-
* phoneManager.subscribe((state) => {
|
|
32
|
-
* console.log('Phone state:', state.status);
|
|
33
|
-
* if (state.status === 'success') {
|
|
34
|
-
* console.log('Phone verified successfully!');
|
|
35
|
-
* }
|
|
36
|
-
* if (state.status === 'error') {
|
|
37
|
-
* console.error('Error:', state.error);
|
|
38
|
-
* }
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* // 4. Start the flow
|
|
42
|
-
* phoneManager.load();
|
|
43
|
-
*
|
|
44
|
-
* // 5. When state is 'inputting', set the phone number
|
|
45
|
-
* phoneManager.setPhoneNumber('+14155551234', true);
|
|
46
|
-
*
|
|
47
|
-
* // 6. Submit the phone number
|
|
48
|
-
* phoneManager.submit();
|
|
49
|
-
*
|
|
50
|
-
* // 7. When state is 'awaitingOtp', submit the OTP code
|
|
51
|
-
* phoneManager.submitOtp('ABC123');
|
|
52
|
-
*
|
|
53
|
-
* // 8. Clean up when done
|
|
54
|
-
* phoneManager.stop();
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* @example Polling-based headless usage
|
|
58
|
-
* ```typescript
|
|
59
|
-
* const phoneManager = createPhoneManager({ config });
|
|
60
|
-
*
|
|
61
|
-
* phoneManager.load();
|
|
62
|
-
*
|
|
63
|
-
* // Poll for state changes
|
|
64
|
-
* const interval = setInterval(() => {
|
|
65
|
-
* const state = phoneManager.getState();
|
|
66
|
-
*
|
|
67
|
-
* switch (state.status) {
|
|
68
|
-
* case 'inputting':
|
|
69
|
-
* phoneManager.setPhoneNumber('+14155551234', true);
|
|
70
|
-
* phoneManager.submit();
|
|
71
|
-
* break;
|
|
72
|
-
* case 'awaitingOtp':
|
|
73
|
-
* // Get OTP from user or external source
|
|
74
|
-
* phoneManager.submitOtp(otpCode);
|
|
75
|
-
* break;
|
|
76
|
-
* case 'success':
|
|
77
|
-
* clearInterval(interval);
|
|
78
|
-
* phoneManager.stop();
|
|
79
|
-
* break;
|
|
80
|
-
* case 'error':
|
|
81
|
-
* clearInterval(interval);
|
|
82
|
-
* console.error(state.error);
|
|
83
|
-
* phoneManager.stop();
|
|
84
|
-
* break;
|
|
85
|
-
* }
|
|
86
|
-
* }, 100);
|
|
87
|
-
* ```
|
|
88
|
-
*/
|
|
89
|
-
import {
|
|
90
|
-
type CreateApiOptions,
|
|
91
|
-
createManager,
|
|
92
|
-
type ManagerSnapshot,
|
|
93
|
-
} from '@incodetech/infra';
|
|
94
|
-
import { type CreatePhoneActorOptions, createPhoneActor } from './phoneActor';
|
|
95
|
-
import type { PhoneMachine } from './phoneStateMachine';
|
|
96
|
-
|
|
97
|
-
type PhoneSnapshot = ManagerSnapshot<PhoneMachine>;
|
|
98
|
-
|
|
99
|
-
/** Phone manager is in initial state, waiting for `load()` to be called */
|
|
100
|
-
export type PhoneIdleState = {
|
|
101
|
-
status: 'idle';
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/** Loading prefilled phone number from backend (if prefill is enabled) */
|
|
105
|
-
export type PhoneLoadingPrefillState = {
|
|
106
|
-
status: 'loadingPrefill';
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Ready for phone input - use `setPhoneNumber()` and `submit()`
|
|
111
|
-
* @property countryCode - ISO country code (e.g., 'US', 'MX')
|
|
112
|
-
* @property phonePrefix - International dialing prefix (e.g., '+1', '+52')
|
|
113
|
-
* @property prefilledPhone - Pre-populated phone number (if prefill enabled)
|
|
114
|
-
* @property phoneError - Validation error message if phone was rejected
|
|
115
|
-
*/
|
|
116
|
-
export type PhoneInputtingState = {
|
|
117
|
-
status: 'inputting';
|
|
118
|
-
countryCode: string;
|
|
119
|
-
phonePrefix: string;
|
|
120
|
-
prefilledPhone?: string;
|
|
121
|
-
phoneError?: string;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/** Phone number is being submitted to the backend */
|
|
125
|
-
export type PhoneSubmittingState = {
|
|
126
|
-
status: 'submitting';
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
/** OTP is being sent to the phone number */
|
|
130
|
-
export type PhoneSendingOtpState = {
|
|
131
|
-
status: 'sendingOtp';
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Waiting for OTP code - use `submitOtp()`, `resendOtp()`, or `back()`
|
|
136
|
-
* @property resendTimer - Seconds remaining before resend is allowed
|
|
137
|
-
* @property canResend - Whether the resend button should be enabled
|
|
138
|
-
* @property attemptsRemaining - Number of OTP verification attempts left
|
|
139
|
-
*/
|
|
140
|
-
export type PhoneAwaitingOtpState = {
|
|
141
|
-
status: 'awaitingOtp';
|
|
142
|
-
resendTimer: number;
|
|
143
|
-
canResend: boolean;
|
|
144
|
-
attemptsRemaining: number;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/** OTP code is being verified against the backend */
|
|
148
|
-
export type PhoneVerifyingOtpState = {
|
|
149
|
-
status: 'verifyingOtp';
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* OTP verification failed - user can retry with `submitOtp()`
|
|
154
|
-
* @property error - Error message describing why verification failed
|
|
155
|
-
* @property attemptsRemaining - Number of remaining attempts before lockout
|
|
156
|
-
*/
|
|
157
|
-
export type PhoneOtpErrorState = {
|
|
158
|
-
status: 'otpError';
|
|
159
|
-
error: string;
|
|
160
|
-
attemptsRemaining: number;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
/** Phone verification completed successfully - call `reset()` to start over */
|
|
164
|
-
export type PhoneSuccessState = {
|
|
165
|
-
status: 'success';
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Fatal error occurred - call `reset()` to start over
|
|
170
|
-
* @property error - Error message describing what went wrong
|
|
171
|
-
*/
|
|
172
|
-
export type PhoneErrorState = {
|
|
173
|
-
status: 'error';
|
|
174
|
-
error: string;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Union of all possible phone manager states.
|
|
179
|
-
* Use discriminated union pattern to narrow the type:
|
|
180
|
-
*
|
|
181
|
-
* @example
|
|
182
|
-
* ```typescript
|
|
183
|
-
* const state = phoneManager.getState();
|
|
184
|
-
* if (state.status === 'inputting') {
|
|
185
|
-
* // TypeScript knows state has countryCode, phonePrefix, etc.
|
|
186
|
-
* console.log(state.countryCode);
|
|
187
|
-
* }
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
export type PhoneState =
|
|
191
|
-
| PhoneIdleState
|
|
192
|
-
| PhoneLoadingPrefillState
|
|
193
|
-
| PhoneInputtingState
|
|
194
|
-
| PhoneSubmittingState
|
|
195
|
-
| PhoneSendingOtpState
|
|
196
|
-
| PhoneAwaitingOtpState
|
|
197
|
-
| PhoneVerifyingOtpState
|
|
198
|
-
| PhoneOtpErrorState
|
|
199
|
-
| PhoneSuccessState
|
|
200
|
-
| PhoneErrorState;
|
|
201
|
-
|
|
202
|
-
function mapState(snapshot: PhoneSnapshot): PhoneState {
|
|
203
|
-
// Type assertion needed because PhoneMachine uses 'as any' for declaration file generation
|
|
204
|
-
const typedSnapshot = snapshot as PhoneSnapshot & {
|
|
205
|
-
matches: (state: string) => boolean;
|
|
206
|
-
context: {
|
|
207
|
-
countryCode: string;
|
|
208
|
-
phonePrefix: string;
|
|
209
|
-
prefilledPhone?: string;
|
|
210
|
-
phoneError?: string;
|
|
211
|
-
resendTimer: number;
|
|
212
|
-
resendTimerActive: boolean;
|
|
213
|
-
attemptsRemaining: number;
|
|
214
|
-
otpError?: string;
|
|
215
|
-
error?: string;
|
|
216
|
-
};
|
|
217
|
-
};
|
|
218
|
-
const { context } = typedSnapshot;
|
|
219
|
-
|
|
220
|
-
if (typedSnapshot.matches('idle')) {
|
|
221
|
-
return { status: 'idle' };
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (typedSnapshot.matches('loadingPrefill')) {
|
|
225
|
-
return { status: 'loadingPrefill' };
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (typedSnapshot.matches('loadingStartInfo')) {
|
|
229
|
-
return {
|
|
230
|
-
status: 'inputting',
|
|
231
|
-
countryCode: context.countryCode,
|
|
232
|
-
phonePrefix: context.phonePrefix,
|
|
233
|
-
prefilledPhone: context.prefilledPhone,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (typedSnapshot.matches('inputting')) {
|
|
238
|
-
return {
|
|
239
|
-
status: 'inputting',
|
|
240
|
-
countryCode: context.countryCode,
|
|
241
|
-
phonePrefix: context.phonePrefix,
|
|
242
|
-
prefilledPhone: context.prefilledPhone,
|
|
243
|
-
phoneError: context.phoneError,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (typedSnapshot.matches('submitting')) {
|
|
248
|
-
return { status: 'submitting' };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (typedSnapshot.matches('sendingOtp')) {
|
|
252
|
-
return { status: 'sendingOtp' };
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (typedSnapshot.matches('awaitingOtp')) {
|
|
256
|
-
return {
|
|
257
|
-
status: 'awaitingOtp',
|
|
258
|
-
resendTimer: context.resendTimer,
|
|
259
|
-
canResend: !context.resendTimerActive,
|
|
260
|
-
attemptsRemaining: context.attemptsRemaining,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (typedSnapshot.matches('verifyingOtp')) {
|
|
265
|
-
return { status: 'verifyingOtp' };
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (typedSnapshot.matches('otpError')) {
|
|
269
|
-
return {
|
|
270
|
-
status: 'otpError',
|
|
271
|
-
error: context.otpError ?? 'Invalid OTP code',
|
|
272
|
-
attemptsRemaining: context.attemptsRemaining,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (typedSnapshot.matches('success')) {
|
|
277
|
-
return { status: 'success' };
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (typedSnapshot.matches('error')) {
|
|
281
|
-
return {
|
|
282
|
-
status: 'error',
|
|
283
|
-
error: context.error ?? 'An error occurred',
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return { status: 'idle' };
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function createApi({ actor }: CreateApiOptions<PhoneMachine>) {
|
|
291
|
-
return {
|
|
292
|
-
/**
|
|
293
|
-
* Initializes the phone verification flow.
|
|
294
|
-
* Transitions from 'idle' to 'loadingPrefill' or 'inputting'.
|
|
295
|
-
* Must be called before any other method.
|
|
296
|
-
*/
|
|
297
|
-
load() {
|
|
298
|
-
actor.send({ type: 'LOAD' });
|
|
299
|
-
},
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Sets the phone number for verification.
|
|
303
|
-
* Should be called when state is 'inputting'.
|
|
304
|
-
*
|
|
305
|
-
* @param phone - Full phone number with country code (e.g., '+14155551234')
|
|
306
|
-
* @param isValid - Whether the phone number passes validation
|
|
307
|
-
*
|
|
308
|
-
* @example
|
|
309
|
-
* ```typescript
|
|
310
|
-
* // Using libphonenumber-js for validation
|
|
311
|
-
* import { isValidPhoneNumber } from 'libphonenumber-js';
|
|
312
|
-
* const phone = '+14155551234';
|
|
313
|
-
* phoneManager.setPhoneNumber(phone, isValidPhoneNumber(phone));
|
|
314
|
-
* ```
|
|
315
|
-
*/
|
|
316
|
-
setPhoneNumber(phone: string, isValid: boolean) {
|
|
317
|
-
actor.send({ type: 'PHONE_CHANGED', phone, isValid });
|
|
318
|
-
},
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Sets the marketing opt-in preference.
|
|
322
|
-
* Only relevant if `config.optinEnabled` is true.
|
|
323
|
-
*
|
|
324
|
-
* @param granted - Whether the user consented to receive marketing messages
|
|
325
|
-
*/
|
|
326
|
-
setOptInGranted(granted: boolean) {
|
|
327
|
-
actor.send({ type: 'OPT_IN_CHANGED', granted });
|
|
328
|
-
},
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Submits the phone number for verification.
|
|
332
|
-
* Requires a valid phone number to be set via `setPhoneNumber()`.
|
|
333
|
-
* Transitions to 'submitting', then to 'sendingOtp' or 'success' (if no OTP).
|
|
334
|
-
*/
|
|
335
|
-
submit() {
|
|
336
|
-
actor.send({ type: 'SUBMIT' });
|
|
337
|
-
},
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Sets the OTP code without submitting.
|
|
341
|
-
* Use this for controlled input components.
|
|
342
|
-
*
|
|
343
|
-
* @param code - The OTP code entered by the user
|
|
344
|
-
*/
|
|
345
|
-
setOtpCode(code: string) {
|
|
346
|
-
actor.send({ type: 'OTP_CHANGED', code });
|
|
347
|
-
},
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Sets and submits the OTP code in one call.
|
|
351
|
-
* Should be called when state is 'awaitingOtp' or 'otpError'.
|
|
352
|
-
*
|
|
353
|
-
* @param code - The complete OTP code (typically 6 alphanumeric characters)
|
|
354
|
-
*
|
|
355
|
-
* @example
|
|
356
|
-
* ```typescript
|
|
357
|
-
* // Submit OTP when user completes entry
|
|
358
|
-
* phoneManager.submitOtp('HH36LP');
|
|
359
|
-
* ```
|
|
360
|
-
*/
|
|
361
|
-
submitOtp(code: string) {
|
|
362
|
-
actor.send({ type: 'OTP_CHANGED', code });
|
|
363
|
-
actor.send({ type: 'VERIFY_OTP' });
|
|
364
|
-
},
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Requests a new OTP code to be sent.
|
|
368
|
-
* Only works when state is 'awaitingOtp' and `canResend` is true.
|
|
369
|
-
* Resets the resend timer.
|
|
370
|
-
*/
|
|
371
|
-
resendOtp() {
|
|
372
|
-
actor.send({ type: 'RESEND_OTP' });
|
|
373
|
-
},
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Returns to the phone input screen from OTP entry.
|
|
377
|
-
* Allows the user to change their phone number.
|
|
378
|
-
* Transitions from 'awaitingOtp' or 'otpError' back to 'inputting'.
|
|
379
|
-
*/
|
|
380
|
-
back() {
|
|
381
|
-
actor.send({ type: 'BACK' });
|
|
382
|
-
},
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Resets the manager to initial state.
|
|
386
|
-
* Can be called from 'success' or 'error' states to start over.
|
|
387
|
-
* Clears all stored data including phone number and OTP.
|
|
388
|
-
*/
|
|
389
|
-
reset() {
|
|
390
|
-
actor.send({ type: 'RESET' });
|
|
391
|
-
},
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Creates a phone verification manager for headless or UI-driven usage.
|
|
397
|
-
*
|
|
398
|
-
* The manager provides a state machine-based API for phone number verification
|
|
399
|
-
* with optional OTP (one-time password) verification.
|
|
400
|
-
*
|
|
401
|
-
* @param options - Configuration options
|
|
402
|
-
* @param options.config - Phone verification configuration
|
|
403
|
-
* @param options.config.otpVerification - Whether to require OTP verification
|
|
404
|
-
* @param options.config.otpExpirationInMinutes - How long the OTP is valid
|
|
405
|
-
* @param options.config.prefill - Whether to fetch a pre-filled phone number
|
|
406
|
-
* @param options.config.isInstantVerify - Use instant verification API
|
|
407
|
-
* @param options.config.optinEnabled - Show marketing opt-in checkbox
|
|
408
|
-
* @param options.config.maxOtpAttempts - Maximum OTP verification attempts (default: 3)
|
|
409
|
-
*
|
|
410
|
-
* @returns Phone manager with state, API methods, and subscription
|
|
411
|
-
*
|
|
412
|
-
* @example Headless usage
|
|
413
|
-
* ```typescript
|
|
414
|
-
* const manager = createPhoneManager({
|
|
415
|
-
* config: { otpVerification: true, otpExpirationInMinutes: 5, prefill: false },
|
|
416
|
-
* });
|
|
417
|
-
*
|
|
418
|
-
* manager.subscribe((state) => console.log(state.status));
|
|
419
|
-
* manager.load();
|
|
420
|
-
* manager.setPhoneNumber('+14155551234', true);
|
|
421
|
-
* manager.submit();
|
|
422
|
-
* // ... wait for 'awaitingOtp' state ...
|
|
423
|
-
* manager.submitOtp('ABC123');
|
|
424
|
-
* manager.stop();
|
|
425
|
-
* ```
|
|
426
|
-
*
|
|
427
|
-
* @example With React/Preact UI hook
|
|
428
|
-
* ```tsx
|
|
429
|
-
* const [state, manager] = useManager(() => createPhoneManager({ config }));
|
|
430
|
-
*
|
|
431
|
-
* if (state.status === 'inputting') {
|
|
432
|
-
* return <input onChange={(e) => manager.setPhoneNumber(e.target.value, true)} />;
|
|
433
|
-
* }
|
|
434
|
-
* ```
|
|
435
|
-
*/
|
|
436
|
-
export function createPhoneManager(options: CreatePhoneActorOptions) {
|
|
437
|
-
const actor = createPhoneActor(options);
|
|
438
|
-
return createManager({ actor, mapState, createApi });
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Type representing a phone manager instance.
|
|
443
|
-
* Includes state access, API methods, and lifecycle management.
|
|
444
|
-
*
|
|
445
|
-
* @property getState - Returns the current PhoneState
|
|
446
|
-
* @property subscribe - Subscribes to state changes, returns unsubscribe function
|
|
447
|
-
* @property stop - Stops the manager and cleans up resources
|
|
448
|
-
* @property load - Initializes the verification flow
|
|
449
|
-
* @property setPhoneNumber - Sets the phone number
|
|
450
|
-
* @property setOptInGranted - Sets marketing opt-in preference
|
|
451
|
-
* @property submit - Submits the phone number
|
|
452
|
-
* @property setOtpCode - Sets OTP code without submitting
|
|
453
|
-
* @property submitOtp - Sets and submits OTP code
|
|
454
|
-
* @property resendOtp - Requests new OTP code
|
|
455
|
-
* @property back - Returns to phone input from OTP screen
|
|
456
|
-
* @property reset - Resets to initial state
|
|
457
|
-
*/
|
|
458
|
-
export type PhoneManager = ReturnType<typeof createPhoneManager>;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { api } from '../http/api';
|
|
2
|
-
import { endpoints } from '../http/endpoints';
|
|
3
|
-
import type {
|
|
4
|
-
AddPhoneParams,
|
|
5
|
-
AddPhoneResponse,
|
|
6
|
-
StartInfo,
|
|
7
|
-
VerifyOtpResponse,
|
|
8
|
-
} from './types';
|
|
9
|
-
|
|
10
|
-
export async function fetchPhone(
|
|
11
|
-
signal?: AbortSignal,
|
|
12
|
-
): Promise<{ phone: string }> {
|
|
13
|
-
const res = await api.get<{ phone: string }>(endpoints.getPhone, { signal });
|
|
14
|
-
if (!res.ok) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
`GET ${endpoints.getPhone} failed: ${res.status} ${res.statusText}`,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
return res.data as { phone: string };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function fetchStartInfo(signal?: AbortSignal): Promise<StartInfo> {
|
|
23
|
-
const res = await api.get<StartInfo>(endpoints.startInfo, { signal });
|
|
24
|
-
if (!res.ok) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`GET ${endpoints.startInfo} failed: ${res.status} ${res.statusText}`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return res.data as StartInfo;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function addPhone(
|
|
33
|
-
params: AddPhoneParams,
|
|
34
|
-
signal?: AbortSignal,
|
|
35
|
-
): Promise<AddPhoneResponse> {
|
|
36
|
-
const res = await api.post<AddPhoneResponse>(
|
|
37
|
-
endpoints.phone,
|
|
38
|
-
{
|
|
39
|
-
phone: params.phone,
|
|
40
|
-
optInGranted: params.optInGranted,
|
|
41
|
-
},
|
|
42
|
-
{ signal },
|
|
43
|
-
);
|
|
44
|
-
if (!res.ok) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
`POST ${endpoints.phone} failed: ${res.status} ${res.statusText}`,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return res.data as AddPhoneResponse;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export async function addPhoneInstantVerify(
|
|
53
|
-
params: AddPhoneParams,
|
|
54
|
-
signal?: AbortSignal,
|
|
55
|
-
): Promise<AddPhoneResponse> {
|
|
56
|
-
const res = await api.post<AddPhoneResponse>(
|
|
57
|
-
endpoints.phoneInstant,
|
|
58
|
-
{
|
|
59
|
-
phone: params.phone,
|
|
60
|
-
optInGranted: params.optInGranted,
|
|
61
|
-
},
|
|
62
|
-
{ signal },
|
|
63
|
-
);
|
|
64
|
-
if (!res.ok) {
|
|
65
|
-
throw new Error(
|
|
66
|
-
`POST ${endpoints.phoneInstant} failed: ${res.status} ${res.statusText}`,
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
return res.data as AddPhoneResponse;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function sendOtp(signal?: AbortSignal): Promise<void> {
|
|
73
|
-
const res = await api.get(
|
|
74
|
-
`${endpoints.sendSmsOtp}?communicationchannel=SMS`,
|
|
75
|
-
{ signal },
|
|
76
|
-
);
|
|
77
|
-
if (!res.ok) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
`GET ${endpoints.sendSmsOtp} failed: ${res.status} ${res.statusText}`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function verifyOtp(
|
|
85
|
-
code: string,
|
|
86
|
-
signal?: AbortSignal,
|
|
87
|
-
): Promise<VerifyOtpResponse> {
|
|
88
|
-
const res = await api.get<VerifyOtpResponse>(
|
|
89
|
-
`${endpoints.compareOtp}?code=${code}&channel=SMS`,
|
|
90
|
-
{ signal },
|
|
91
|
-
);
|
|
92
|
-
if (!res.ok) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`GET ${endpoints.compareOtp} failed: ${res.status} ${res.statusText}`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
return res.data as VerifyOtpResponse;
|
|
98
|
-
}
|