@pubflow/react 0.4.4 → 0.4.6
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/index.cjs +318 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +319 -14
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -254,6 +254,7 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
254
254
|
});
|
|
255
255
|
const apiClient = new core.ApiClient(fullConfig, storage);
|
|
256
256
|
const authService = new core.AuthService(apiClient, storage, fullConfig);
|
|
257
|
+
const twoFactorService = new core.TwoFactorService(apiClient, fullConfig);
|
|
257
258
|
// Get current user (non-blocking)
|
|
258
259
|
let user = null;
|
|
259
260
|
let isAuthenticated = false;
|
|
@@ -261,12 +262,35 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
261
262
|
config: fullConfig,
|
|
262
263
|
apiClient,
|
|
263
264
|
authService,
|
|
265
|
+
twoFactorService,
|
|
264
266
|
user,
|
|
265
267
|
isAuthenticated,
|
|
266
268
|
isLoading: true,
|
|
269
|
+
twoFactorPending: false,
|
|
270
|
+
twoFactorMethods: [],
|
|
267
271
|
login: async (credentials) => {
|
|
268
272
|
const result = await authService.login(credentials);
|
|
269
|
-
if (
|
|
273
|
+
if (!isMounted)
|
|
274
|
+
return result;
|
|
275
|
+
if (result.success && result.requires2fa) {
|
|
276
|
+
// 2FA required — keep session pending, expose methods
|
|
277
|
+
setContextValue(prev => {
|
|
278
|
+
var _a;
|
|
279
|
+
return ({
|
|
280
|
+
...prev,
|
|
281
|
+
instances: {
|
|
282
|
+
...prev.instances,
|
|
283
|
+
[instanceConfig.id]: {
|
|
284
|
+
...prev.instances[instanceConfig.id],
|
|
285
|
+
isLoading: false,
|
|
286
|
+
twoFactorPending: true,
|
|
287
|
+
twoFactorMethods: (_a = result.availableMethods) !== null && _a !== void 0 ? _a : [],
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
else if (result.success && result.user) {
|
|
270
294
|
setContextValue(prev => ({
|
|
271
295
|
...prev,
|
|
272
296
|
instances: {
|
|
@@ -275,7 +299,9 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
275
299
|
...prev.instances[instanceConfig.id],
|
|
276
300
|
user: result.user,
|
|
277
301
|
isAuthenticated: true,
|
|
278
|
-
isLoading: false
|
|
302
|
+
isLoading: false,
|
|
303
|
+
twoFactorPending: false,
|
|
304
|
+
twoFactorMethods: [],
|
|
279
305
|
}
|
|
280
306
|
}
|
|
281
307
|
}));
|
|
@@ -293,7 +319,9 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
293
319
|
...prev.instances[instanceConfig.id],
|
|
294
320
|
user: null,
|
|
295
321
|
isAuthenticated: false,
|
|
296
|
-
isLoading: false
|
|
322
|
+
isLoading: false,
|
|
323
|
+
twoFactorPending: false,
|
|
324
|
+
twoFactorMethods: [],
|
|
297
325
|
}
|
|
298
326
|
}
|
|
299
327
|
}));
|
|
@@ -316,7 +344,31 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
316
344
|
}));
|
|
317
345
|
}
|
|
318
346
|
return result;
|
|
319
|
-
}
|
|
347
|
+
},
|
|
348
|
+
verifyTwoFactor: async (methodId, code) => {
|
|
349
|
+
const result = await twoFactorService.verify(methodId, code, 'login');
|
|
350
|
+
if (result.verified && isMounted) {
|
|
351
|
+
// Fetch the now-active user from the server
|
|
352
|
+
const userData = await authService.getCurrentUser();
|
|
353
|
+
setContextValue(prev => ({
|
|
354
|
+
...prev,
|
|
355
|
+
instances: {
|
|
356
|
+
...prev.instances,
|
|
357
|
+
[instanceConfig.id]: {
|
|
358
|
+
...prev.instances[instanceConfig.id],
|
|
359
|
+
user: userData,
|
|
360
|
+
isAuthenticated: true,
|
|
361
|
+
twoFactorPending: false,
|
|
362
|
+
twoFactorMethods: [],
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
return result;
|
|
368
|
+
},
|
|
369
|
+
startTwoFactor: async (methodId, method) => {
|
|
370
|
+
return twoFactorService.start(methodId, method, 'login');
|
|
371
|
+
},
|
|
320
372
|
};
|
|
321
373
|
// Load user asynchronously
|
|
322
374
|
authService.getCurrentUser().then(currentUser => {
|
|
@@ -365,16 +417,39 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
365
417
|
});
|
|
366
418
|
const apiClient = new core.ApiClient(fullConfig, storage);
|
|
367
419
|
const authService = new core.AuthService(apiClient, storage, fullConfig);
|
|
420
|
+
const twoFactorService = new core.TwoFactorService(apiClient, fullConfig);
|
|
368
421
|
instancesMap[defaultInstance] = {
|
|
369
422
|
config: fullConfig,
|
|
370
423
|
apiClient,
|
|
371
424
|
authService,
|
|
425
|
+
twoFactorService,
|
|
372
426
|
user: null,
|
|
373
427
|
isAuthenticated: false,
|
|
374
428
|
isLoading: true,
|
|
429
|
+
twoFactorPending: false,
|
|
430
|
+
twoFactorMethods: [],
|
|
375
431
|
login: async (credentials) => {
|
|
376
432
|
const result = await authService.login(credentials);
|
|
377
|
-
if (
|
|
433
|
+
if (!isMounted)
|
|
434
|
+
return result;
|
|
435
|
+
if (result.success && result.requires2fa) {
|
|
436
|
+
setContextValue(prev => {
|
|
437
|
+
var _a;
|
|
438
|
+
return ({
|
|
439
|
+
...prev,
|
|
440
|
+
instances: {
|
|
441
|
+
...prev.instances,
|
|
442
|
+
[defaultInstance]: {
|
|
443
|
+
...prev.instances[defaultInstance],
|
|
444
|
+
isLoading: false,
|
|
445
|
+
twoFactorPending: true,
|
|
446
|
+
twoFactorMethods: (_a = result.availableMethods) !== null && _a !== void 0 ? _a : [],
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
else if (result.success && result.user) {
|
|
378
453
|
setContextValue(prev => ({
|
|
379
454
|
...prev,
|
|
380
455
|
instances: {
|
|
@@ -383,7 +458,9 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
383
458
|
...prev.instances[defaultInstance],
|
|
384
459
|
user: result.user,
|
|
385
460
|
isAuthenticated: true,
|
|
386
|
-
isLoading: false
|
|
461
|
+
isLoading: false,
|
|
462
|
+
twoFactorPending: false,
|
|
463
|
+
twoFactorMethods: [],
|
|
387
464
|
}
|
|
388
465
|
}
|
|
389
466
|
}));
|
|
@@ -401,7 +478,9 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
401
478
|
...prev.instances[defaultInstance],
|
|
402
479
|
user: null,
|
|
403
480
|
isAuthenticated: false,
|
|
404
|
-
isLoading: false
|
|
481
|
+
isLoading: false,
|
|
482
|
+
twoFactorPending: false,
|
|
483
|
+
twoFactorMethods: [],
|
|
405
484
|
}
|
|
406
485
|
}
|
|
407
486
|
}));
|
|
@@ -424,7 +503,30 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
424
503
|
}));
|
|
425
504
|
}
|
|
426
505
|
return result;
|
|
427
|
-
}
|
|
506
|
+
},
|
|
507
|
+
verifyTwoFactor: async (methodId, code) => {
|
|
508
|
+
const result = await twoFactorService.verify(methodId, code, 'login');
|
|
509
|
+
if (result.verified && isMounted) {
|
|
510
|
+
const userData = await authService.getCurrentUser();
|
|
511
|
+
setContextValue(prev => ({
|
|
512
|
+
...prev,
|
|
513
|
+
instances: {
|
|
514
|
+
...prev.instances,
|
|
515
|
+
[defaultInstance]: {
|
|
516
|
+
...prev.instances[defaultInstance],
|
|
517
|
+
user: userData,
|
|
518
|
+
isAuthenticated: true,
|
|
519
|
+
twoFactorPending: false,
|
|
520
|
+
twoFactorMethods: [],
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}));
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
},
|
|
527
|
+
startTwoFactor: async (methodId, method) => {
|
|
528
|
+
return twoFactorService.start(methodId, method, 'login');
|
|
529
|
+
},
|
|
428
530
|
};
|
|
429
531
|
// Load user asynchronously
|
|
430
532
|
authService.getCurrentUser().then(currentUser => {
|
|
@@ -526,9 +628,13 @@ function useAuth(instanceId) {
|
|
|
526
628
|
user: null,
|
|
527
629
|
isAuthenticated: false,
|
|
528
630
|
isLoading: true, // Crucial: tell the UI we are still loading the provider
|
|
631
|
+
twoFactorPending: false,
|
|
632
|
+
twoFactorMethods: [],
|
|
529
633
|
login: async () => { throw new Error('Pubflow not initialized yet'); },
|
|
530
634
|
logout: async () => { throw new Error('Pubflow not initialized yet'); },
|
|
531
635
|
validateSession: async () => ({ isValid: false }),
|
|
636
|
+
verifyTwoFactor: async () => ({ success: false, error: 'Pubflow not initialized yet' }),
|
|
637
|
+
startTwoFactor: async () => ({ success: false, error: 'Pubflow not initialized yet' }),
|
|
532
638
|
};
|
|
533
639
|
}
|
|
534
640
|
// After provider is ready, if the instance is STILL missing, it's a real config error.
|
|
@@ -540,9 +646,13 @@ function useAuth(instanceId) {
|
|
|
540
646
|
user: pubflowInstance.user || null,
|
|
541
647
|
isAuthenticated: pubflowInstance.isAuthenticated,
|
|
542
648
|
isLoading: pubflowInstance.isLoading,
|
|
649
|
+
twoFactorPending: pubflowInstance.twoFactorPending,
|
|
650
|
+
twoFactorMethods: pubflowInstance.twoFactorMethods,
|
|
543
651
|
login: pubflowInstance.login,
|
|
544
652
|
logout: pubflowInstance.logout,
|
|
545
|
-
validateSession: pubflowInstance.validateSession
|
|
653
|
+
validateSession: pubflowInstance.validateSession,
|
|
654
|
+
verifyTwoFactor: pubflowInstance.verifyTwoFactor,
|
|
655
|
+
startTwoFactor: pubflowInstance.startTwoFactor,
|
|
546
656
|
};
|
|
547
657
|
}
|
|
548
658
|
|
|
@@ -8647,17 +8757,25 @@ function processLogoUrl(logoUrl) {
|
|
|
8647
8757
|
* Professional login form component
|
|
8648
8758
|
*/
|
|
8649
8759
|
function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccountCreation, instanceId }) {
|
|
8650
|
-
const { login, isLoading } = useAuth(instanceId);
|
|
8760
|
+
const { login, verifyTwoFactor, startTwoFactor, isLoading } = useAuth(instanceId);
|
|
8651
8761
|
// Form state
|
|
8652
8762
|
const [email, setEmail] = React.useState('');
|
|
8653
8763
|
const [password, setPassword] = React.useState('');
|
|
8654
8764
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
8655
8765
|
const [error, setError] = React.useState('');
|
|
8656
8766
|
const [rememberMe, setRememberMe] = React.useState(false);
|
|
8767
|
+
// 2FA state
|
|
8768
|
+
const [step, setStep] = React.useState('credentials');
|
|
8769
|
+
const [otpCode, setOtpCode] = React.useState('');
|
|
8770
|
+
const [pendingMethods, setPendingMethods] = React.useState([]);
|
|
8771
|
+
const [activeMethodId, setActiveMethodId] = React.useState(null);
|
|
8772
|
+
const [activeMethodName, setActiveMethodName] = React.useState('email');
|
|
8773
|
+
const [otpLoading, setOtpLoading] = React.useState(false);
|
|
8657
8774
|
// Configuration with defaults
|
|
8658
8775
|
const { primaryColor = process.env.REACT_APP_PRIMARY_COLOR || '#006aff', secondaryColor = process.env.REACT_APP_SECONDARY_COLOR || '#4a90e2', appName = process.env.REACT_APP_NAME || 'Pubflow', logo = process.env.REACT_APP_LOGO, showPasswordReset = true, showAccountCreation = true, className = '', redirectPath } = config;
|
|
8659
8776
|
// Handle form submission
|
|
8660
8777
|
const handleSubmit = async (e) => {
|
|
8778
|
+
var _a;
|
|
8661
8779
|
e.preventDefault();
|
|
8662
8780
|
setError('');
|
|
8663
8781
|
// Basic validation
|
|
@@ -8671,6 +8789,17 @@ function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccount
|
|
|
8671
8789
|
}
|
|
8672
8790
|
try {
|
|
8673
8791
|
const result = await login({ email: email.toLowerCase().trim(), password });
|
|
8792
|
+
if (result.requires2fa) {
|
|
8793
|
+
// Switch to OTP step
|
|
8794
|
+
const methods = (_a = result.availableMethods) !== null && _a !== void 0 ? _a : [];
|
|
8795
|
+
setPendingMethods(methods);
|
|
8796
|
+
if (methods.length > 0) {
|
|
8797
|
+
setActiveMethodId(methods[0].id);
|
|
8798
|
+
setActiveMethodName(methods[0].method);
|
|
8799
|
+
}
|
|
8800
|
+
setStep('otp');
|
|
8801
|
+
return;
|
|
8802
|
+
}
|
|
8674
8803
|
if (result.success) {
|
|
8675
8804
|
if (onSuccess) {
|
|
8676
8805
|
onSuccess(result.user);
|
|
@@ -8696,6 +8825,56 @@ function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccount
|
|
|
8696
8825
|
}
|
|
8697
8826
|
}
|
|
8698
8827
|
};
|
|
8828
|
+
// Handle OTP verification
|
|
8829
|
+
const handleOtpSubmit = async (e) => {
|
|
8830
|
+
e.preventDefault();
|
|
8831
|
+
if (!activeMethodId)
|
|
8832
|
+
return;
|
|
8833
|
+
setError('');
|
|
8834
|
+
setOtpLoading(true);
|
|
8835
|
+
try {
|
|
8836
|
+
const result = await verifyTwoFactor(activeMethodId, otpCode.trim());
|
|
8837
|
+
if (result.verified) {
|
|
8838
|
+
if (onSuccess)
|
|
8839
|
+
onSuccess(null);
|
|
8840
|
+
if (redirectPath && typeof window !== 'undefined') {
|
|
8841
|
+
window.location.href = redirectPath;
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8844
|
+
else {
|
|
8845
|
+
const msg = result.error ||
|
|
8846
|
+
(result.attempts_remaining !== undefined
|
|
8847
|
+
? `Incorrect code. ${result.attempts_remaining} attempt(s) remaining.`
|
|
8848
|
+
: 'Incorrect code.');
|
|
8849
|
+
setError(msg);
|
|
8850
|
+
if (onError)
|
|
8851
|
+
onError(msg);
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
catch (err) {
|
|
8855
|
+
const msg = err instanceof Error ? err.message : 'Verification failed';
|
|
8856
|
+
setError(msg);
|
|
8857
|
+
if (onError)
|
|
8858
|
+
onError(msg);
|
|
8859
|
+
}
|
|
8860
|
+
finally {
|
|
8861
|
+
setOtpLoading(false);
|
|
8862
|
+
}
|
|
8863
|
+
};
|
|
8864
|
+
// Handle resend code
|
|
8865
|
+
const handleResend = async () => {
|
|
8866
|
+
if (!activeMethodId)
|
|
8867
|
+
return;
|
|
8868
|
+
setError('');
|
|
8869
|
+
setOtpLoading(true);
|
|
8870
|
+
try {
|
|
8871
|
+
await startTwoFactor(activeMethodId, activeMethodName);
|
|
8872
|
+
}
|
|
8873
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
8874
|
+
finally {
|
|
8875
|
+
setOtpLoading(false);
|
|
8876
|
+
}
|
|
8877
|
+
};
|
|
8699
8878
|
// Dynamic styles
|
|
8700
8879
|
const styles = {
|
|
8701
8880
|
container: {
|
|
@@ -8711,6 +8890,7 @@ function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccount
|
|
|
8711
8890
|
},
|
|
8712
8891
|
logoSection: {
|
|
8713
8892
|
display: 'flex',
|
|
8893
|
+
flexDirection: 'column',
|
|
8714
8894
|
justifyContent: 'center',
|
|
8715
8895
|
alignItems: 'center',
|
|
8716
8896
|
textAlign: 'center',
|
|
@@ -8833,11 +9013,17 @@ function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccount
|
|
|
8833
9013
|
textAlign: 'center'
|
|
8834
9014
|
}
|
|
8835
9015
|
};
|
|
8836
|
-
return (jsxRuntime.jsxs("div", { className: className, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsxRuntime.jsx("img", { src: processLogoUrl(logo), alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsxRuntime.jsxs("h1", { style: styles.welcomeText, children: ["Welcome to ", appName] }), jsxRuntime.jsx("p", { style: styles.subtitleText, children:
|
|
9016
|
+
return (jsxRuntime.jsxs("div", { className: className, style: styles.container, children: [jsxRuntime.jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsxRuntime.jsx("img", { src: processLogoUrl(logo), alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsxRuntime.jsxs("h1", { style: styles.welcomeText, children: ["Welcome to ", appName] }), jsxRuntime.jsx("p", { style: styles.subtitleText, children: step === 'otp' ? 'Enter the verification code we sent you.' : 'Sign in to your account' })] }), error && (jsxRuntime.jsxs("div", { style: styles.errorContainer, children: [jsxRuntime.jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsxRuntime.jsx("span", { style: styles.errorText, children: error })] })), step === 'otp' ? (jsxRuntime.jsxs("form", { onSubmit: handleOtpSubmit, children: [jsxRuntime.jsxs("div", { style: styles.inputGroup, children: [jsxRuntime.jsx("label", { style: styles.inputLabel, children: "Verification Code" }), jsxRuntime.jsxs("div", { style: styles.inputContainer, children: [jsxRuntime.jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD10" }), jsxRuntime.jsx("input", { type: "text", inputMode: "numeric", pattern: "[0-9]*", maxLength: 6, style: { ...styles.input, letterSpacing: '0.4em', textAlign: 'center' }, placeholder: "000000", value: otpCode, onChange: (e) => setOtpCode(e.target.value.replace(/\D/g, '')), autoFocus: true, autoComplete: "one-time-code", disabled: otpLoading, required: true })] })] }), jsxRuntime.jsx("button", { type: "submit", style: {
|
|
9017
|
+
...styles.loginButton,
|
|
9018
|
+
opacity: otpLoading || otpCode.length < 6 ? 0.7 : 1,
|
|
9019
|
+
cursor: otpLoading || otpCode.length < 6 ? 'not-allowed' : 'pointer',
|
|
9020
|
+
}, disabled: otpLoading || otpCode.length < 6, children: otpLoading ? '⟳ Verifying…' : 'Verify Code' }), jsxRuntime.jsxs("div", { style: { textAlign: 'center', marginTop: '16px' }, children: [jsxRuntime.jsx("button", { type: "button", style: { ...styles.linkButton, fontSize: '14px' }, onClick: handleResend, disabled: otpLoading, children: "Didn't receive a code? Resend" }), jsxRuntime.jsx("button", { type: "button", style: { ...styles.linkButton, fontSize: '13px', color: '#888' }, onClick: () => { setStep('credentials'); setError(''); setOtpCode(''); }, children: "\u2190 Back to login" })] })] })) : (
|
|
9021
|
+
/* ── Credentials Step ── */
|
|
9022
|
+
jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [jsxRuntime.jsxs("div", { style: styles.inputGroup, children: [jsxRuntime.jsx("label", { style: styles.inputLabel, children: "Email Address" }), jsxRuntime.jsxs("div", { style: styles.inputContainer, children: [jsxRuntime.jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsxRuntime.jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: email, onChange: (e) => setEmail(e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] })] }), jsxRuntime.jsxs("div", { style: styles.inputGroup, children: [jsxRuntime.jsx("label", { style: styles.inputLabel, children: "Password" }), jsxRuntime.jsxs("div", { style: styles.inputContainer, children: [jsxRuntime.jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsxRuntime.jsx("input", { type: showPassword ? 'text' : 'password', style: styles.input, placeholder: "Enter your password", value: password, onChange: (e) => setPassword(e.target.value), autoComplete: "current-password", disabled: isLoading, required: true }), jsxRuntime.jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowPassword(!showPassword), disabled: isLoading, children: showPassword ? '👁' : '👁🗨' })] })] }), jsxRuntime.jsxs("div", { style: styles.checkboxContainer, children: [jsxRuntime.jsxs("label", { style: { display: 'flex', alignItems: 'center', fontSize: '14px', color: '#666' }, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: rememberMe, onChange: (e) => setRememberMe(e.target.checked), style: { marginRight: '8px' } }), "Remember me"] }), showPasswordReset && (jsxRuntime.jsx("button", { type: "button", style: { ...styles.linkButton, fontSize: '14px' }, onClick: onPasswordReset, disabled: isLoading, children: "Forgot password?" }))] }), jsxRuntime.jsx("button", { type: "submit", style: {
|
|
8837
9023
|
...styles.loginButton,
|
|
8838
9024
|
opacity: isLoading ? 0.8 : 1,
|
|
8839
9025
|
cursor: isLoading ? 'not-allowed' : 'pointer'
|
|
8840
|
-
}, disabled: isLoading, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { style: { animation: 'spin 1s linear infinite' }, children: "\u27F3" }), "Signing in..."] })) : ('Sign In') })
|
|
9026
|
+
}, disabled: isLoading, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { style: { animation: 'spin 1s linear infinite' }, children: "\u27F3" }), "Signing in..."] })) : ('Sign In') }), showAccountCreation && (jsxRuntime.jsx("div", { style: styles.accountActions, children: jsxRuntime.jsx("button", { type: "button", style: styles.linkButton, onClick: onAccountCreation, disabled: isLoading, children: "Create New Account" }) }))] })), jsxRuntime.jsx("style", { children: `
|
|
8841
9027
|
@keyframes spin {
|
|
8842
9028
|
from { transform: rotate(0deg); }
|
|
8843
9029
|
to { transform: rotate(360deg); }
|
|
@@ -9850,6 +10036,125 @@ function useBridgeApiRaw(instanceId) {
|
|
|
9850
10036
|
};
|
|
9851
10037
|
}
|
|
9852
10038
|
|
|
10039
|
+
/**
|
|
10040
|
+
* useTwoFactor Hook for React
|
|
10041
|
+
*
|
|
10042
|
+
* Convenience hook for managing 2FA settings (setup, toggle, remove).
|
|
10043
|
+
* For the LOGIN-TIME 2FA flow use useAuth() which surfaces
|
|
10044
|
+
* twoFactorPending / verifyTwoFactor / startTwoFactor.
|
|
10045
|
+
*/
|
|
10046
|
+
/**
|
|
10047
|
+
* Hook for managing 2FA settings.
|
|
10048
|
+
*
|
|
10049
|
+
* Must be used inside a PubflowProvider.
|
|
10050
|
+
*
|
|
10051
|
+
* @param instanceId Optional Pubflow instance ID
|
|
10052
|
+
*/
|
|
10053
|
+
function useTwoFactor(instanceId) {
|
|
10054
|
+
const context = React.useContext(PubflowContext);
|
|
10055
|
+
if (!context)
|
|
10056
|
+
throw new Error('useTwoFactor must be used within a PubflowProvider');
|
|
10057
|
+
const id = instanceId || context.defaultInstance;
|
|
10058
|
+
const instance = context.instances[id];
|
|
10059
|
+
const [systemEnabled, setSystemEnabled] = React.useState(false);
|
|
10060
|
+
const [availableMethods, setAvailableMethods] = React.useState([]);
|
|
10061
|
+
const [methods, setMethods] = React.useState([]);
|
|
10062
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
10063
|
+
const [error, setError] = React.useState(null);
|
|
10064
|
+
const refresh = React.useCallback(async () => {
|
|
10065
|
+
if (!instance)
|
|
10066
|
+
return;
|
|
10067
|
+
setIsLoading(true);
|
|
10068
|
+
setError(null);
|
|
10069
|
+
try {
|
|
10070
|
+
const [sys, userMethods] = await Promise.all([
|
|
10071
|
+
instance.twoFactorService.getSystem(),
|
|
10072
|
+
instance.twoFactorService.getMethods(),
|
|
10073
|
+
]);
|
|
10074
|
+
setSystemEnabled(sys.global_two_factor_enabled);
|
|
10075
|
+
setAvailableMethods(sys.available_methods);
|
|
10076
|
+
setMethods(userMethods);
|
|
10077
|
+
}
|
|
10078
|
+
catch (e) {
|
|
10079
|
+
setError((e === null || e === void 0 ? void 0 : e.message) || 'Failed to load 2FA info');
|
|
10080
|
+
}
|
|
10081
|
+
finally {
|
|
10082
|
+
setIsLoading(false);
|
|
10083
|
+
}
|
|
10084
|
+
}, [instance]);
|
|
10085
|
+
const setup = React.useCallback(async (method, identifier) => {
|
|
10086
|
+
if (!instance)
|
|
10087
|
+
return { success: false, error: 'Pubflow not initialized' };
|
|
10088
|
+
setIsLoading(true);
|
|
10089
|
+
setError(null);
|
|
10090
|
+
try {
|
|
10091
|
+
const result = await instance.twoFactorService.setup(method, identifier);
|
|
10092
|
+
if (result.success)
|
|
10093
|
+
await refresh();
|
|
10094
|
+
return result;
|
|
10095
|
+
}
|
|
10096
|
+
catch (e) {
|
|
10097
|
+
const msg = (e === null || e === void 0 ? void 0 : e.message) || 'Setup failed';
|
|
10098
|
+
setError(msg);
|
|
10099
|
+
return { success: false, error: msg };
|
|
10100
|
+
}
|
|
10101
|
+
finally {
|
|
10102
|
+
setIsLoading(false);
|
|
10103
|
+
}
|
|
10104
|
+
}, [instance, refresh]);
|
|
10105
|
+
const toggle = React.useCallback(async (enabled, verificationCode, verificationMethodId) => {
|
|
10106
|
+
if (!instance)
|
|
10107
|
+
return { success: false, error: 'Pubflow not initialized' };
|
|
10108
|
+
setIsLoading(true);
|
|
10109
|
+
setError(null);
|
|
10110
|
+
try {
|
|
10111
|
+
const result = await instance.twoFactorService.toggle(enabled, verificationCode, verificationMethodId);
|
|
10112
|
+
if (result.success)
|
|
10113
|
+
await refresh();
|
|
10114
|
+
return result;
|
|
10115
|
+
}
|
|
10116
|
+
catch (e) {
|
|
10117
|
+
const msg = (e === null || e === void 0 ? void 0 : e.message) || 'Toggle failed';
|
|
10118
|
+
setError(msg);
|
|
10119
|
+
return { success: false, error: msg };
|
|
10120
|
+
}
|
|
10121
|
+
finally {
|
|
10122
|
+
setIsLoading(false);
|
|
10123
|
+
}
|
|
10124
|
+
}, [instance, refresh]);
|
|
10125
|
+
const removeMethod = React.useCallback(async (methodId, verificationCode, verificationMethodId) => {
|
|
10126
|
+
if (!instance)
|
|
10127
|
+
return { success: false, error: 'Pubflow not initialized' };
|
|
10128
|
+
setIsLoading(true);
|
|
10129
|
+
setError(null);
|
|
10130
|
+
try {
|
|
10131
|
+
const result = await instance.twoFactorService.removeMethod(methodId, verificationCode, verificationMethodId);
|
|
10132
|
+
if (result.success)
|
|
10133
|
+
await refresh();
|
|
10134
|
+
return result;
|
|
10135
|
+
}
|
|
10136
|
+
catch (e) {
|
|
10137
|
+
const msg = (e === null || e === void 0 ? void 0 : e.message) || 'Remove failed';
|
|
10138
|
+
setError(msg);
|
|
10139
|
+
return { success: false, error: msg };
|
|
10140
|
+
}
|
|
10141
|
+
finally {
|
|
10142
|
+
setIsLoading(false);
|
|
10143
|
+
}
|
|
10144
|
+
}, [instance, refresh]);
|
|
10145
|
+
return {
|
|
10146
|
+
systemEnabled,
|
|
10147
|
+
availableMethods,
|
|
10148
|
+
methods,
|
|
10149
|
+
isLoading,
|
|
10150
|
+
error,
|
|
10151
|
+
refresh,
|
|
10152
|
+
setup,
|
|
10153
|
+
toggle,
|
|
10154
|
+
removeMethod,
|
|
10155
|
+
};
|
|
10156
|
+
}
|
|
10157
|
+
|
|
9853
10158
|
/**
|
|
9854
10159
|
* Search Query Builder Hook for React
|
|
9855
10160
|
*
|
|
@@ -10102,6 +10407,7 @@ exports.useRequireAuth = useRequireAuth;
|
|
|
10102
10407
|
exports.useSearchQueryBuilder = useSearchQueryBuilder;
|
|
10103
10408
|
exports.useSimpleAuthGuard = useSimpleAuthGuard;
|
|
10104
10409
|
exports.useTheme = useTheme;
|
|
10410
|
+
exports.useTwoFactor = useTwoFactor;
|
|
10105
10411
|
Object.keys(core).forEach(function (k) {
|
|
10106
10412
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
10107
10413
|
enumerable: true,
|