@auth0/auth0-acul-react 1.0.0-alpha.1 → 1.0.0-alpha.3
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 +214 -11
- package/dist/export/getting-started.d.ts +1 -1
- package/dist/export/hooks.d.ts +1 -1
- package/dist/hooks/common/errors.d.ts +19 -19
- package/dist/hooks/common/errors.js +1 -1
- package/dist/hooks/common/errors.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/utility/passkey-autofill.d.ts +86 -0
- package/dist/hooks/utility/passkey-autofill.js +2 -0
- package/dist/hooks/utility/passkey-autofill.js.map +1 -0
- package/dist/hooks/utility/polling-manager.d.ts +1 -0
- package/dist/hooks/utility/polling-manager.js.map +1 -1
- package/dist/hooks/utility/validate-password.js +1 -1
- package/dist/hooks/utility/validate-password.js.map +1 -1
- package/dist/hooks/utility/validate-username.js +1 -1
- package/dist/hooks/utility/validate-username.js.map +1 -1
- package/dist/screens/accept-invitation.d.ts +1 -1
- package/dist/screens/accept-invitation.js.map +1 -1
- package/dist/screens/consent.d.ts +1 -1
- package/dist/screens/consent.js.map +1 -1
- package/dist/screens/customized-consent.d.ts +1 -1
- package/dist/screens/customized-consent.js.map +1 -1
- package/dist/screens/device-code-activation-allowed.d.ts +1 -1
- package/dist/screens/device-code-activation-allowed.js.map +1 -1
- package/dist/screens/device-code-activation-denied.d.ts +1 -1
- package/dist/screens/device-code-activation-denied.js.map +1 -1
- package/dist/screens/device-code-activation.d.ts +1 -1
- package/dist/screens/device-code-activation.js.map +1 -1
- package/dist/screens/device-code-confirmation.d.ts +1 -1
- package/dist/screens/device-code-confirmation.js.map +1 -1
- package/dist/screens/email-identifier-challenge.d.ts +1 -1
- package/dist/screens/email-identifier-challenge.js.map +1 -1
- package/dist/screens/email-otp-challenge.d.ts +1 -1
- package/dist/screens/email-otp-challenge.js.map +1 -1
- package/dist/screens/email-verification-result.d.ts +1 -1
- package/dist/screens/email-verification-result.js.map +1 -1
- package/dist/screens/interstitial-captcha.d.ts +1 -1
- package/dist/screens/interstitial-captcha.js.map +1 -1
- package/dist/screens/login-email-verification.d.ts +1 -1
- package/dist/screens/login-email-verification.js.map +1 -1
- package/dist/screens/login-id.d.ts +2 -1
- package/dist/screens/login-id.js +1 -1
- package/dist/screens/login-id.js.map +1 -1
- package/dist/screens/login-password.d.ts +3 -2
- package/dist/screens/login-password.js +1 -1
- package/dist/screens/login-password.js.map +1 -1
- package/dist/screens/login-passwordless-email-code.d.ts +1 -1
- package/dist/screens/login-passwordless-email-code.js.map +1 -1
- package/dist/screens/login-passwordless-sms-otp.d.ts +1 -1
- package/dist/screens/login-passwordless-sms-otp.js.map +1 -1
- package/dist/screens/login.d.ts +1 -1
- package/dist/screens/login.js.map +1 -1
- package/dist/screens/logout-aborted.d.ts +1 -1
- package/dist/screens/logout-aborted.js.map +1 -1
- package/dist/screens/logout-complete.d.ts +1 -1
- package/dist/screens/logout-complete.js.map +1 -1
- package/dist/screens/logout.d.ts +1 -1
- package/dist/screens/logout.js.map +1 -1
- package/dist/screens/mfa-begin-enroll-options.d.ts +1 -1
- package/dist/screens/mfa-begin-enroll-options.js.map +1 -1
- package/dist/screens/mfa-country-codes.d.ts +1 -1
- package/dist/screens/mfa-country-codes.js.map +1 -1
- package/dist/screens/mfa-detect-browser-capabilities.d.ts +1 -1
- package/dist/screens/mfa-detect-browser-capabilities.js.map +1 -1
- package/dist/screens/mfa-email-challenge.d.ts +1 -1
- package/dist/screens/mfa-email-challenge.js.map +1 -1
- package/dist/screens/mfa-email-list.d.ts +1 -1
- package/dist/screens/mfa-email-list.js.map +1 -1
- package/dist/screens/mfa-enroll-result.d.ts +1 -1
- package/dist/screens/mfa-enroll-result.js.map +1 -1
- package/dist/screens/mfa-login-options.d.ts +3 -2
- package/dist/screens/mfa-login-options.js +1 -1
- package/dist/screens/mfa-login-options.js.map +1 -1
- package/dist/screens/mfa-otp-challenge.d.ts +1 -1
- package/dist/screens/mfa-otp-challenge.js.map +1 -1
- package/dist/screens/mfa-otp-enrollment-code.d.ts +1 -1
- package/dist/screens/mfa-otp-enrollment-code.js.map +1 -1
- package/dist/screens/mfa-otp-enrollment-qr.d.ts +1 -1
- package/dist/screens/mfa-otp-enrollment-qr.js.map +1 -1
- package/dist/screens/mfa-phone-challenge.d.ts +1 -1
- package/dist/screens/mfa-phone-challenge.js.map +1 -1
- package/dist/screens/mfa-phone-enrollment.d.ts +1 -1
- package/dist/screens/mfa-phone-enrollment.js.map +1 -1
- package/dist/screens/mfa-push-challenge-push.d.ts +1 -1
- package/dist/screens/mfa-push-challenge-push.js.map +1 -1
- package/dist/screens/mfa-push-enrollment-qr.d.ts +4 -2
- package/dist/screens/mfa-push-enrollment-qr.js +1 -1
- package/dist/screens/mfa-push-enrollment-qr.js.map +1 -1
- package/dist/screens/mfa-push-list.d.ts +1 -1
- package/dist/screens/mfa-push-list.js.map +1 -1
- package/dist/screens/mfa-push-welcome.d.ts +1 -1
- package/dist/screens/mfa-push-welcome.js.map +1 -1
- package/dist/screens/mfa-recovery-code-challenge-new-code.d.ts +1 -1
- package/dist/screens/mfa-recovery-code-challenge-new-code.js.map +1 -1
- package/dist/screens/mfa-recovery-code-challenge.d.ts +1 -1
- package/dist/screens/mfa-recovery-code-challenge.js.map +1 -1
- package/dist/screens/mfa-recovery-code-enrollment.d.ts +1 -1
- package/dist/screens/mfa-recovery-code-enrollment.js.map +1 -1
- package/dist/screens/mfa-sms-challenge.d.ts +1 -1
- package/dist/screens/mfa-sms-challenge.js.map +1 -1
- package/dist/screens/mfa-sms-enrollment.d.ts +1 -1
- package/dist/screens/mfa-sms-enrollment.js.map +1 -1
- package/dist/screens/mfa-sms-list.d.ts +1 -1
- package/dist/screens/mfa-sms-list.js.map +1 -1
- package/dist/screens/mfa-voice-challenge.d.ts +1 -1
- package/dist/screens/mfa-voice-challenge.js.map +1 -1
- package/dist/screens/mfa-voice-enrollment.d.ts +1 -1
- package/dist/screens/mfa-voice-enrollment.js.map +1 -1
- package/dist/screens/mfa-webauthn-change-key-nickname.d.ts +1 -1
- package/dist/screens/mfa-webauthn-change-key-nickname.js.map +1 -1
- package/dist/screens/mfa-webauthn-enrollment-success.d.ts +1 -1
- package/dist/screens/mfa-webauthn-enrollment-success.js.map +1 -1
- package/dist/screens/mfa-webauthn-error.d.ts +1 -1
- package/dist/screens/mfa-webauthn-error.js.map +1 -1
- package/dist/screens/mfa-webauthn-not-available-error.d.ts +1 -1
- package/dist/screens/mfa-webauthn-not-available-error.js.map +1 -1
- package/dist/screens/mfa-webauthn-platform-challenge.d.ts +1 -1
- package/dist/screens/mfa-webauthn-platform-challenge.js.map +1 -1
- package/dist/screens/mfa-webauthn-platform-enrollment.d.ts +1 -1
- package/dist/screens/mfa-webauthn-platform-enrollment.js.map +1 -1
- package/dist/screens/mfa-webauthn-roaming-challenge.d.ts +1 -1
- package/dist/screens/mfa-webauthn-roaming-challenge.js.map +1 -1
- package/dist/screens/mfa-webauthn-roaming-enrollment.d.ts +1 -1
- package/dist/screens/mfa-webauthn-roaming-enrollment.js.map +1 -1
- package/dist/screens/organization-picker.d.ts +1 -1
- package/dist/screens/organization-picker.js.map +1 -1
- package/dist/screens/organization-selection.d.ts +1 -1
- package/dist/screens/organization-selection.js.map +1 -1
- package/dist/screens/passkey-enrollment-local.d.ts +1 -1
- package/dist/screens/passkey-enrollment-local.js.map +1 -1
- package/dist/screens/passkey-enrollment.d.ts +1 -1
- package/dist/screens/passkey-enrollment.js.map +1 -1
- package/dist/screens/phone-identifier-challenge.d.ts +3 -1
- package/dist/screens/phone-identifier-challenge.js +1 -1
- package/dist/screens/phone-identifier-challenge.js.map +1 -1
- package/dist/screens/phone-identifier-enrollment.d.ts +1 -1
- package/dist/screens/phone-identifier-enrollment.js.map +1 -1
- package/dist/screens/redeem-ticket.d.ts +1 -1
- package/dist/screens/redeem-ticket.js.map +1 -1
- package/dist/screens/reset-password-email.d.ts +1 -1
- package/dist/screens/reset-password-email.js.map +1 -1
- package/dist/screens/reset-password-error.d.ts +1 -1
- package/dist/screens/reset-password-error.js.map +1 -1
- package/dist/screens/reset-password-mfa-email-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-email-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-otp-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-otp-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-phone-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-phone-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-push-challenge-push.d.ts +1 -1
- package/dist/screens/reset-password-mfa-push-challenge-push.js.map +1 -1
- package/dist/screens/reset-password-mfa-recovery-code-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-recovery-code-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-sms-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-sms-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-voice-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-voice-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-webauthn-platform-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-webauthn-platform-challenge.js.map +1 -1
- package/dist/screens/reset-password-mfa-webauthn-roaming-challenge.d.ts +1 -1
- package/dist/screens/reset-password-mfa-webauthn-roaming-challenge.js.map +1 -1
- package/dist/screens/reset-password-request.d.ts +1 -1
- package/dist/screens/reset-password-request.js.map +1 -1
- package/dist/screens/reset-password-success.d.ts +1 -1
- package/dist/screens/reset-password-success.js.map +1 -1
- package/dist/screens/reset-password.d.ts +1 -1
- package/dist/screens/reset-password.js.map +1 -1
- package/dist/screens/signup-id.d.ts +1 -1
- package/dist/screens/signup-id.js.map +1 -1
- package/dist/screens/signup-password.d.ts +3 -2
- package/dist/screens/signup-password.js +1 -1
- package/dist/screens/signup-password.js.map +1 -1
- package/dist/screens/signup.d.ts +1 -1
- package/dist/screens/signup.js.map +1 -1
- package/dist/state/error-store.d.ts +14 -14
- package/dist/state/error-store.js +1 -1
- package/dist/state/error-store.js.map +1 -1
- package/dist/telemetry.js +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Auth0 ACUL React SDK
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
|
|
3
5
|
<div align="center">
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/@auth0/auth0-acul-react)
|
|
@@ -11,7 +13,7 @@
|
|
|
11
13
|
|
|
12
14
|
<div align='center'>
|
|
13
15
|
|
|
14
|
-
📚 [Documentation](
|
|
16
|
+
📚 [Documentation](#documentation) | 🚀 [Getting Started](#getting-started) | 💻 [API Reference](#api-reference) | 🪝 [Hooks](#hooks) | [Examples](#examples) | 💬 [Feedback](#feedback)
|
|
15
17
|
|
|
16
18
|
</div>
|
|
17
19
|
|
|
@@ -23,7 +25,24 @@ Developers using Auth0’s Universal Login can use this React SDK to customize s
|
|
|
23
25
|
>
|
|
24
26
|
> This feature is still in **Early Access**.
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
<a id="documentation"></a>
|
|
29
|
+
## 📚 Documentation
|
|
30
|
+
|
|
31
|
+
- [Quickstart](https://auth0.com/docs/customize/login-pages/advanced-customizations/getting-started/sdk-quickstart) - our guide for setting up the SDK on your app.
|
|
32
|
+
- [Guides](https://auth0.com/docs/customize/login-pages/advanced-customizations/screens) - more guides for common use cases
|
|
33
|
+
- [Examples](https://github.com/auth0/universal-login/tree/master/packages/auth0-acul-react/examples) - code snippets for different customization use cases.
|
|
34
|
+
|
|
35
|
+
<a id="getting-started"></a>
|
|
36
|
+
## 🚀 Getting started
|
|
37
|
+
|
|
38
|
+
### Prerequisites
|
|
39
|
+
Before starting, ensure that you have the following setup:
|
|
40
|
+
|
|
41
|
+
1. **Custom Domain**: Ensure that a custom domain is configured for your Auth0 tenant.
|
|
42
|
+
2. **Screen Configuration**: Set up the required authentication screens within your Auth0 flow.
|
|
43
|
+
For detailed steps, refer to the [Configure ACUL Screens](https://auth0.com/docs/customize/login-pages/advanced-customizations/getting-started/configure-acul-screens).
|
|
44
|
+
|
|
45
|
+
### Installation
|
|
27
46
|
|
|
28
47
|
```bash
|
|
29
48
|
npm install @auth0/auth0-acul-react
|
|
@@ -33,11 +52,13 @@ Peer dependency:
|
|
|
33
52
|
```bash
|
|
34
53
|
npm install react
|
|
35
54
|
```
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
The SDK supports `partial imports` for each screen, allowing you to include only the code you need for your specific use case. This helps keep your bundle size small and improves performance.
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
|
|
56
|
+
### Importing the SDK
|
|
57
|
+
The SDK supports `partial imports` for each screen, allowing you to include only the code you need for your specific use case. This helps keep your bundle size small and improves performance.
|
|
58
|
+
|
|
59
|
+
Also, you can use a `root import` to load all screens from a single bundle if your app requires it.
|
|
60
|
+
|
|
61
|
+
#### Partial Imports
|
|
41
62
|
Each screen has its own set of hooks and methods. You can import only what you need for the screen you're building.
|
|
42
63
|
|
|
43
64
|
The following example shows how to import and use SDK to build `login-id` screen.
|
|
@@ -71,7 +92,7 @@ import {
|
|
|
71
92
|
|
|
72
93
|
---
|
|
73
94
|
|
|
74
|
-
|
|
95
|
+
#### Root Imports
|
|
75
96
|
|
|
76
97
|
The SDK also supports a root import, which lets you load all screens from a single bundle.
|
|
77
98
|
This is useful if your app dynamically renders different screens at runtime based on the current Auth0 flow, for example, when you want one unified build that can handle all possible screens.
|
|
@@ -94,7 +115,7 @@ import {
|
|
|
94
115
|
```
|
|
95
116
|
---
|
|
96
117
|
|
|
97
|
-
|
|
118
|
+
#### Types / Interfaces
|
|
98
119
|
Typescript types and interfaces can be imported from `@auth0/auth0-acul-react/types` for type safety and better DX.
|
|
99
120
|
```tsx
|
|
100
121
|
import type {
|
|
@@ -106,14 +127,196 @@ import type {
|
|
|
106
127
|
// ...other types
|
|
107
128
|
} from '@auth0/auth0-acul-react/types';
|
|
108
129
|
```
|
|
109
|
-
Refer to our [API Reference](
|
|
130
|
+
Refer to our [API Reference](#api-reference) for the full list of available types and interfaces.
|
|
110
131
|
|
|
111
132
|
---
|
|
112
133
|
|
|
134
|
+
<a id="api-reference"></a>
|
|
135
|
+
## 💻 API Reference
|
|
136
|
+
### Screens
|
|
137
|
+
|
|
138
|
+
| No. | Prompt | Screen Name | Documentation Link |
|
|
139
|
+
|--------|--------------------|-------------------|--------------------------------------------------------------------------------------------|
|
|
140
|
+
| 1 | login | login | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login) |
|
|
141
|
+
| 2 | login-id | login-id | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login-Id) |
|
|
142
|
+
| 3 | login-password | login-password | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login-Password) |
|
|
143
|
+
| 4 | signup-id | signup-id | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Signup-Id) |
|
|
144
|
+
| 5 | signup-password | signup-password | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Signup-Password) |
|
|
145
|
+
|
|
146
|
+
<details>
|
|
147
|
+
<summary>Explore more screens...</summary>
|
|
148
|
+
|
|
149
|
+
| No. | Prompt | Screen Name | Documentation Link |
|
|
150
|
+
|--------|--------------------------------|-------------------------------------------|-------------------------------------------------------------------------------------------------------|
|
|
151
|
+
| 6 | login-passwordless | login-passwordless-email-code | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login-Passwordless-Email-Code) |
|
|
152
|
+
| 7 | login-passwordless | login-passwordless-sms-otp | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login-Passwordless-Sms-Otp) |
|
|
153
|
+
| 8 | passkeys | passkey-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Passkey-Enrollment) |
|
|
154
|
+
| 9 | passkeys | passkey-enrollment-local | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Passkey-Enrollment-Local) |
|
|
155
|
+
| 10 | phone-identifier-enrollment | phone-identifier-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Phone-Identifier-Enrollment) |
|
|
156
|
+
| 11 | phone-identifier-challenge | phone-identifier-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Phone-Identifier-Challenge) |
|
|
157
|
+
| 12 | email-identifier-challenge | email-identifier-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Email-Identifier-Challenge) |
|
|
158
|
+
| 13 | captcha | interstitial-captcha | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Interstitial-Captcha) |
|
|
159
|
+
| 14 | reset-password | reset-password-email | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Email) |
|
|
160
|
+
| 15 | reset-password | reset-password-request | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Request) |
|
|
161
|
+
| 16 | reset-password | reset-password | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password) |
|
|
162
|
+
| 17 | reset-password | reset-password-error | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Error) |
|
|
163
|
+
| 18 | reset-password | reset-password-success | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Success) |
|
|
164
|
+
| 19 | signup | signup | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Signup) |
|
|
165
|
+
| 20 | mfa | mfa-detect-browser-capabilities | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Detect-Browser-Capabilities) |
|
|
166
|
+
| 21 | mfa | mfa-enroll-result | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Enroll-Result) |
|
|
167
|
+
| 22 | mfa | mfa-begin-enroll-options | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Begin-Enroll-Options) |
|
|
168
|
+
| 23 | mfa | mfa-login-options | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Login-Options) |
|
|
169
|
+
| 24 | mfa-push | mfa-push-enrollment-qr | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Push-Enrollment-Qr) |
|
|
170
|
+
| 25 | mfa-push | mfa-push-welcome | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Push-Welcome) |
|
|
171
|
+
| 26 | mfa-push | mfa-push-challenge-push | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Push-Challenge-Push) |
|
|
172
|
+
| 27 | mfa-push | mfa-push-list | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Push-List) |
|
|
173
|
+
| 28 | mfa-sms | mfa-country-codes | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Country-Codes) |
|
|
174
|
+
| 29 | mfa-sms | mfa-sms-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Sms-Challenge) |
|
|
175
|
+
| 30 | mfa-sms | mfa-sms-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Sms-Enrollment) |
|
|
176
|
+
| 31 | mfa-sms | mfa-sms-list | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Sms-List) |
|
|
177
|
+
| 32 | mfa-email | mfa-email-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Email-Challenge) |
|
|
178
|
+
| 33 | mfa-email | mfa-email-list | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Email-List) |
|
|
179
|
+
| 34 | invitatino | accept-invitation | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Accept-Invitation) |
|
|
180
|
+
| 35 | organizations | organization-picker | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Organization-Picker) |
|
|
181
|
+
| 36 | organizations | organization-selection | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Organization-Selection) |
|
|
182
|
+
| 37 | reset-password | mfa-otp-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Otp-Challenge) |
|
|
183
|
+
| 38 | mfa-otp | mfa-otp-enrollment-code | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Otp-Enrollment-Code) |
|
|
184
|
+
| 39 | mfa-otp | mfa-otp-enrollment-qr | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Otp-Enrollment-Qr) |
|
|
185
|
+
| 40 | reset-password | reset-password-mfa-email-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Email-Challenge) |
|
|
186
|
+
| 41 | reset-password | reset-password-mfa-push-challenge-push | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Push-Challenge-Push)|
|
|
187
|
+
| 42 | reset-password | mfa-sms-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Sms-Challenge) |
|
|
188
|
+
| 43 | reset-password | reset-password-mfa-otp-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Organization-Selection) |
|
|
189
|
+
| 44 | mfa-phone | mfa-phone-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Phone-Enrollment) |
|
|
190
|
+
| 45 | mfa-voice | mfa-voice-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Voice-Enrollment) |
|
|
191
|
+
| 46 | mfa-recovery-code | mfa-recovery-code-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Recovery-Code-Challenge) |
|
|
192
|
+
| 47 | device-flow | device-code-activation-allowed | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Device-Code-Activation-Allowed) |
|
|
193
|
+
| 48 | device-flow | device-code-activation-denied | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Device-Code-Activation-Denied) |
|
|
194
|
+
| 49 | device-flow | device-code-activation | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Device-Code-Activation) |
|
|
195
|
+
| 50 | reset-password | reset-password-mfa-recovery-code-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Recovery-Code-Challenge) |
|
|
196
|
+
| 51 | reset-password | reset-password-mfa-voice | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Voice-Challenge) |
|
|
197
|
+
| 52 | common | redeem-ticket | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Redeem-Ticket) |
|
|
198
|
+
| 53 | device-flow | device-code-confirmation | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Device-Code-Confirmation) |
|
|
199
|
+
| 54 | mfa-phone | mfa-phone-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Phone-Challenge) |
|
|
200
|
+
| 55 | mfa-voice | mfa-voice-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Voice-Challenge) |
|
|
201
|
+
| 56 | mfa-recovery-code | mfa-recovery-code-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Recovery-Code-Enrollment) |
|
|
202
|
+
| 57 | reset-password | reset-password-mfa-phone-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-Phone-Challenge) |
|
|
203
|
+
| 58 | mfa-recovery-code | mfa-recovery-code-challenge-new-code | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-Recovery-Code-Challenge-New-Code) |
|
|
204
|
+
| 59 | logout | logout | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Logout) |
|
|
205
|
+
| 60 | logout | logout-aborted | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Logout-Aborted) |
|
|
206
|
+
| 61 | logout | logout-complete | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Logout-Complete) |
|
|
207
|
+
| 62 | email-verification | email-verification-result | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Email-Verification-Result) |
|
|
208
|
+
| 63 | login-email-verification | login-email-verification | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Login-Email-Verification) |
|
|
209
|
+
| 64 |mfa-webauthn | mfa-webauthn-platform-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Platform-Enrollment) |
|
|
210
|
+
| 65 |mfa-webauthn | mfa-webauthn-error | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Error) |
|
|
211
|
+
| 66 |mfa-webauthn | mfa-webauthn-roaming-enrollment | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Roaming-Enrollment) |
|
|
212
|
+
| 67 |mfa-webauthn | mfa-webauthn-roaming-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Roaming-Challenge) |
|
|
213
|
+
| 68 |mfa-webauthn | mfa-webauthn-platform-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Platform-Challenge) |
|
|
214
|
+
| 69 |mfa-webauthn | mfa-webauthn-enrollment-success | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Enrollment-Success) |
|
|
215
|
+
| 70 |mfa-webauthn | mfa-webauthn-change-key-nickname | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Change-Key-Nickname) |
|
|
216
|
+
| 71 |mfa-webauthn | mfa-webauthn-not-available-error | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Mfa-WebAuthn-Not-Available-Error) |
|
|
217
|
+
| 72 |reset-password | reset-password-mfa-webauthn-platform-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-WebAuthn-Platform-Challenge) |
|
|
218
|
+
| 73 |reset-password | reset-password-mfa-webauthn-roaming-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Reset-Password-Mfa-WebAuthn-Roaming-Challenge) |
|
|
219
|
+
| 74 |consent | consent | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.consent) |
|
|
220
|
+
| 75 |customized-consent | customized-consent | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Customized-Consent) |
|
|
221
|
+
| 76 |email-otp-challenge | email-otp-challenge | [Link](https://auth0.github.io/universal-login/auth0-acul-react/modules/Screens.Email-OTP-Challenge) |
|
|
222
|
+
</details>
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Hooks
|
|
227
|
+
### Context Hooks (Available in all screens)
|
|
228
|
+
- `useUser()` - Current user information
|
|
229
|
+
- `useTenant()` - Tenant configuration
|
|
230
|
+
- `useClient()` - Application client information
|
|
231
|
+
- `useScreen()` - Current screen data and configuration
|
|
232
|
+
- `useTransaction()` - Transaction state and methods
|
|
233
|
+
- `useBranding()` - Tenant branding and theme
|
|
234
|
+
- `useOrganization()` - Organization context (if applicable)
|
|
235
|
+
- `usePrompt()` - Current authentication prompt
|
|
236
|
+
- `useUntrustedData()` - Untrusted data from the authentication flow
|
|
237
|
+
|
|
238
|
+
### Utility Hooks
|
|
239
|
+
Specialized hooks for form validation, polling, and identifier management:
|
|
240
|
+
|
|
241
|
+
#### Identifier Management
|
|
242
|
+
- `useLoginIdentifiers()` - Get available login identifier types (email, phone, username)
|
|
243
|
+
- `useSignupIdentifiers()` - Get available signup identifier types, each with its `required` status
|
|
244
|
+
|
|
245
|
+
#### Form Validation
|
|
246
|
+
- `usePasswordValidation(password, rules)` - Real-time password strength validation
|
|
247
|
+
- `useUsernameValidation(username)` - Username format and availability validation
|
|
248
|
+
|
|
249
|
+
#### MFA & Polling
|
|
250
|
+
- `useMfaPolling(options)` - Manage MFA push notification polling lifecycle
|
|
251
|
+
- `useResend(options)` - Handle resend operations with cooldown timers
|
|
252
|
+
|
|
253
|
+
### Common Hooks
|
|
254
|
+
General-purpose hooks available across all screens:
|
|
255
|
+
|
|
256
|
+
#### Screen Management
|
|
257
|
+
- `useCurrentScreen()` - Get complete current screen context data
|
|
258
|
+
- `useAuth0Themes()` - Access tenant branding and theme configuration
|
|
259
|
+
|
|
260
|
+
#### Error Handling
|
|
261
|
+
- `useErrors(options)` - Comprehensive error management with categorization
|
|
262
|
+
- Filter by error kind: `'validation'`, `'auth0'`, `'configuration'`
|
|
263
|
+
- Filter by field name for form-specific errors
|
|
264
|
+
- Dismiss individual or all errors
|
|
265
|
+
|
|
266
|
+
### Screen-Specific Action Methods
|
|
267
|
+
Each screen module exports methods for screen actions:
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
// Login ID Screen
|
|
271
|
+
import {
|
|
272
|
+
loginMethod,
|
|
273
|
+
continueWithFederatedLogin
|
|
274
|
+
} from '@auth0/auth0-acul-react/login-id';
|
|
275
|
+
|
|
276
|
+
// Password Screen
|
|
277
|
+
import {
|
|
278
|
+
loginMethod,
|
|
279
|
+
forgotPasswordMethod
|
|
280
|
+
} from '@auth0/auth0-acul-react/login-password';
|
|
281
|
+
|
|
282
|
+
// MFA Push Challenge
|
|
283
|
+
import {
|
|
284
|
+
continueMethod,
|
|
285
|
+
resendPushNotification,
|
|
286
|
+
useMfaPolling
|
|
287
|
+
} from '@auth0/auth0-acul-react/mfa-push-challenge-push';
|
|
288
|
+
```
|
|
289
|
+
|
|
113
290
|
## Examples
|
|
114
|
-
|
|
291
|
+
- [React Examples](https://github.com/auth0/universal-login/tree/master/packages/auth0-acul-react/examples) - Complete React component examples
|
|
292
|
+
- [React Boilerplate](https://github.com/auth0/auth0-acul-react-boilerplate) - Full React application template
|
|
115
293
|
|
|
116
294
|
---
|
|
295
|
+
|
|
296
|
+
<a id="feedback"></a>
|
|
297
|
+
## 💬 Feedback
|
|
298
|
+
|
|
299
|
+
### Contributing
|
|
300
|
+
|
|
301
|
+
We appreciate feedback and contribution to this repo! Before you get started, please see the following:
|
|
302
|
+
|
|
303
|
+
- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
|
|
304
|
+
- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
|
|
305
|
+
|
|
306
|
+
### Raise an issue
|
|
307
|
+
|
|
308
|
+
To provide feedback or report a bug, please [raise an issue on our issue tracker](https://github.com/auth0/universal-login/issues).
|
|
309
|
+
|
|
310
|
+
### Vulnerability Reporting
|
|
311
|
+
|
|
312
|
+
Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/responsible-disclosure-policy) details the procedure for disclosing security issues.
|
|
313
|
+
|
|
314
|
+
### Legal
|
|
315
|
+
|
|
316
|
+
**Early Access.** This SDK and its associated product are made available only in Early Access ("EA") format and are governed by the Free Trial terms of the [Okta Master Subscription Agreement](https://www.okta.com/agreements/#mastersubscriptionagreement). If Okta elects to make a version of this SDK and its associated product Generally Available ("GA"), such GA version may have different pricing, product and feature configurations, and use of the GA product and SDK will be subject to the standard terms of the Agreement (or other such titled written or electronic agreement addressing the same subject matter) between Okta and Customer."
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
117
320
|
<p align="center">
|
|
118
321
|
<picture>
|
|
119
322
|
<source media="(prefers-color-scheme: light)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
|
|
@@ -208,7 +208,7 @@
|
|
|
208
208
|
*
|
|
209
209
|
* #### Error Handling
|
|
210
210
|
* - `useErrors(options)` - Comprehensive error management with categorization
|
|
211
|
-
* - Filter by error
|
|
211
|
+
* - Filter by error type: `'validation'`, `'auth0'`, `'configuration'`
|
|
212
212
|
* - Filter by field name for form-specific errors
|
|
213
213
|
* - Dismiss individual or all errors
|
|
214
214
|
*
|
package/dist/export/hooks.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { usePasswordValidation, useUsernameValidation, useResend, useMfaPolling, useErrors, useAuth0Themes, useCurrentScreen, useLoginIdentifiers, useSignupIdentifiers, } from '../hooks';
|
|
1
|
+
export { usePasswordValidation, useUsernameValidation, useResend, useMfaPolling, useErrors, useAuth0Themes, useCurrentScreen, useLoginIdentifiers, useSignupIdentifiers, usePasskeyAutofill, } from '../hooks';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type ErrorItem, type
|
|
1
|
+
import { type ErrorItem, type ErrorType } from '../../state/error-store';
|
|
2
2
|
export interface ErrorsResult extends ReadonlyArray<ErrorItem> {
|
|
3
|
-
|
|
3
|
+
byType(type: ErrorType, opts?: {
|
|
4
4
|
field?: string;
|
|
5
5
|
}): ReadonlyArray<ErrorItem>;
|
|
6
6
|
byField(field: string, opts?: {
|
|
7
|
-
|
|
7
|
+
type?: ErrorType;
|
|
8
8
|
}): ReadonlyArray<ErrorItem>;
|
|
9
9
|
}
|
|
10
10
|
export interface UseErrorOptions {
|
|
@@ -18,21 +18,21 @@ export interface UseErrorsResult {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* React hook for reading and managing errors in ACUL (Advanced Customization of Universal Login).
|
|
21
|
-
* With all validation and server-side errors. It groups errors into three
|
|
22
|
-
* - `
|
|
23
|
-
* - `
|
|
24
|
-
* - `
|
|
21
|
+
* With all validation and server-side errors. It groups errors into three types:
|
|
22
|
+
* - `auth0` — errors returned by Auth0 or your own backend.
|
|
23
|
+
* - `validation` — errors from client-side validation (e.g., invalid form input).
|
|
24
|
+
* - `configuration` — errors caused by incorrect integration or SDK misuse.
|
|
25
25
|
*
|
|
26
26
|
* @supportedScreens
|
|
27
27
|
* - The `useErrors` hook is available on every ACUL screen.
|
|
28
28
|
*
|
|
29
|
-
* @param options.includeDevErrors - When `true`,
|
|
29
|
+
* @param options.includeDevErrors - When `true`, configuration errors are included in
|
|
30
30
|
* the returned list. Defaults to `false`.
|
|
31
31
|
*
|
|
32
32
|
* @returns An object of type {@link UseErrorsResult}, containing:
|
|
33
33
|
* - `errors` — the full error list of type {@link ErrorsResult}, with helpers:
|
|
34
|
-
* - `errors.
|
|
35
|
-
* - `errors.byField(field, filter?)` — filter by field and optionally by
|
|
34
|
+
* - `errors.byType(type, filter?)` — filter by error type and optionally by field.
|
|
35
|
+
* - `errors.byField(field, filter?)` — filter by field and optionally by type.
|
|
36
36
|
* - `hasError` — `true` if any error is currently present.
|
|
37
37
|
* - `dismiss(id)` — remove a specific error by its ID.
|
|
38
38
|
* - `dismissAll()` — clear all tracked errors.
|
|
@@ -51,7 +51,7 @@ export interface UseErrorsResult {
|
|
|
51
51
|
* <div>
|
|
52
52
|
* {hasError && (
|
|
53
53
|
* <div className="mb-4">
|
|
54
|
-
* {errors.
|
|
54
|
+
* {errors.byType("auth0").map(err => (
|
|
55
55
|
* <div key={err.id} className="text-red-600">
|
|
56
56
|
* {err.message}
|
|
57
57
|
* <button onClick={() => dismiss(err.id)}>Dismiss</button>
|
|
@@ -66,12 +66,12 @@ export interface UseErrorsResult {
|
|
|
66
66
|
* }
|
|
67
67
|
* ```
|
|
68
68
|
*
|
|
69
|
-
* In addition to rendering messages, you can filter by field or
|
|
69
|
+
* In addition to rendering messages, you can filter by field or type:
|
|
70
70
|
* ```ts
|
|
71
|
-
* console.log(errors.
|
|
72
|
-
* console.log(errors.
|
|
71
|
+
* console.log(errors.byType('validation')); // all validation errors
|
|
72
|
+
* console.log(errors.byType('validation', { field: 'username' })); // validation errors for field 'username'
|
|
73
73
|
* console.log(errors.byField('username')); // all errors for field 'username'
|
|
74
|
-
* console.log(errors.byField('username', {
|
|
74
|
+
* console.log(errors.byField('username', { type: 'auth0' })); // auth0 errors for field 'username'
|
|
75
75
|
* ```
|
|
76
76
|
*/
|
|
77
77
|
export declare function useErrors(options?: UseErrorOptions): UseErrorsResult;
|
|
@@ -83,11 +83,11 @@ declare function withError<T>(actionOrPromise: (() => T | Promise<T>) | Promise<
|
|
|
83
83
|
*/
|
|
84
84
|
export declare const errorManager: {
|
|
85
85
|
withError: typeof withError;
|
|
86
|
-
|
|
86
|
+
replaceValidationErrors(list: Array<Omit<ErrorItem, "id">>, opts?: {
|
|
87
87
|
byField?: string;
|
|
88
88
|
}): void;
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
clearValidationErrors(): void;
|
|
90
|
+
pushValidationErrors(list: Omit<ErrorItem, "id"> | Array<Omit<ErrorItem, "id">>): void;
|
|
91
91
|
replaceDeveloperErrors(list: Array<Omit<ErrorItem, "id">>, opts?: {
|
|
92
92
|
byField?: string;
|
|
93
93
|
}): void;
|
|
@@ -100,4 +100,4 @@ export declare const errorManager: {
|
|
|
100
100
|
pushServerErrors(list: Omit<ErrorItem, "id"> | Array<Omit<ErrorItem, "id">>): void;
|
|
101
101
|
syncServerErrors(): void;
|
|
102
102
|
};
|
|
103
|
-
export { ErrorItem,
|
|
103
|
+
export { ErrorItem, ErrorType };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getErrors as
|
|
1
|
+
import{getErrors as r,ValidationError as e,ConfigurationError as t,Auth0Error as a}from"@auth0/auth0-acul-js";import{useSyncExternalStore as o,useRef as n,useEffect as i,useMemo as c,useCallback as l}from"react";import{errorStore as s,ERROR_TYPES as u}from"../../state/error-store.js";function f(r,e){return e?r.filter(r=>r.field===e):r}const p=new WeakMap,d=new WeakMap,h=new WeakMap,v=(r,e)=>{const t="auth0"===r?p:"validation"===r?d:h,a=t.get(e);if(a)return a;const o=Object.freeze(e.map(e=>Object.freeze({...e,type:r})));return t.set(e,o),o};function b(e={}){const{includeDevErrors:t=!1}=e,a=o(r=>s.subscribe(r),()=>s.snapshot()),p=n(!1);i(()=>{if(p.current)return;p.current=!0;const e=r?.()??[];s.replace("auth0",e)},[]);const d=c(()=>v("auth0",a.auth0),[a.auth0]),h=c(()=>v("validation",a.validation),[a.validation]),b=c(()=>v("configuration",a.configuration),[a.configuration]),y=c(()=>Object.freeze([...t?b:[],...h,...d]),[t,b,h,d]),E=c(()=>{const r=Object.assign([...y],{byType(r,e){let t;return t="validation"===r?h:"configuration"===r?b:d,e?.field?Object.freeze(f(t,e.field)):t},byField:(e,t)=>t?.type?r.byType(t.type,{field:e}):Object.freeze(f(y,e))});return Object.freeze(r)},[y,h,b,d]),g=y.length>0,m=l(r=>{s.remove(u,r)},[]),w=l(()=>{s.clear(u)},[]);return c(()=>({errors:E,hasError:g,dismiss:m,dismissAll:w}),[E,g,m,w])}const y={withError:function(r){const o=r=>{const o=function(r){return r instanceof e?"validation":r instanceof t?"configuration":r instanceof a?"auth0":null}(r),n=function(r){return{code:r?.code??(r instanceof Error?r.name:void 0)??"unknown_error",message:r?.message??"Unknown error",field:r?.field}}(r);switch(o){case"validation":y.replaceValidationErrors([n]);break;case"configuration":y.replaceDeveloperErrors([n]);break;case"auth0":y.replaceServerErrors([n]);break;default:throw console.error("[auth0-acul-react] Unhandled error:",r),r}};if("function"==typeof r)try{const e=r();return"object"==typeof(n=e)&&null!==n&&"then"in n&&"function"==typeof n.then?e.catch(r=>{throw o(r),r}):e}catch(r){throw o(r),r}var n;return r.catch(r=>{throw o(r),r})},replaceValidationErrors(r,e){e?.byField?s.replacePartial("validation",r,e.byField):s.replace("validation",r)},clearValidationErrors(){s.clear(["validation"])},pushValidationErrors(r){s.push("validation",r)},replaceDeveloperErrors(r,e){e?.byField?s.replacePartial("configuration",r,e.byField):s.replace("configuration",r)},clearDeveloperErrors(){s.clear(["configuration"])},pushDeveloperErrors(r){s.push("configuration",r)},replaceServerErrors(r,e){e?.byField?s.replacePartial("auth0",r,e.byField):s.replace("auth0",r)},clearServerErrors(){s.clear(["auth0"])},pushServerErrors(r){s.push("auth0",r)},syncServerErrors(){const e=r?.()??[];s.replace("auth0",e)}};export{y as errorManager,b as useErrors};
|
|
2
2
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sources":["../../../src/hooks/common/errors.ts"],"sourcesContent":["import {\n SDKUsageError,\n UserInputError,\n Auth0ServerError,\n getErrors as getServerErrors,\n type Error as Auth0Error,\n} from '@auth0/auth0-acul-js';\nimport { useEffect, useMemo, useRef, useSyncExternalStore, useCallback } from 'react';\n\nimport { errorStore, ERROR_KINDS, type ErrorItem, type ErrorKind } from '../../state/error-store';\n\nexport interface ErrorsResult extends ReadonlyArray<ErrorItem> {\n byKind(kind: ErrorKind, opts?: { field?: string }): ReadonlyArray<ErrorItem>;\n byField(field: string, opts?: { kind?: ErrorKind }): ReadonlyArray<ErrorItem>;\n}\n\nexport interface UseErrorOptions {\n includeDevErrors?: boolean;\n}\n\nexport interface UseErrorsResult {\n errors: ErrorsResult;\n hasError: boolean;\n dismiss: (id: string) => void;\n dismissAll: () => void;\n}\n\nfunction classifyKind(e: unknown): ErrorKind | null {\n if (e instanceof UserInputError) {\n return 'client';\n }\n if (e instanceof SDKUsageError) {\n return 'developer';\n }\n if (e instanceof Auth0ServerError) {\n return 'server';\n }\n return null;\n}\n\nfunction toErrorObject(e: unknown): Omit<ErrorItem, 'id'> {\n return {\n code: (e as Auth0Error)?.code ?? (e instanceof Error ? e.name : undefined) ?? 'unknown_error',\n message: (e as Auth0Error)?.message ?? 'Unknown error',\n field: (e as Auth0Error)?.field,\n };\n}\n\nfunction filterByField<T extends { field?: string }>(\n list: ReadonlyArray<T>,\n field?: string\n): ReadonlyArray<T> {\n if (!field) {\n return list;\n }\n return list.filter((e) => e.field === field);\n}\n\n// caches for tagging\nconst cacheServer = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\nconst cacheClient = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\nconst cacheDev = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\n\nconst tag = (kind: ErrorKind, arr: ReadonlyArray<ErrorItem>): ReadonlyArray<ErrorItem> => {\n const cache = kind === 'server' ? cacheServer : kind === 'client' ? cacheClient : cacheDev;\n const hit = cache.get(arr);\n if (hit) {\n return hit;\n }\n const out = Object.freeze(arr.map((e) => Object.freeze({ ...e, kind })));\n cache.set(arr, out);\n return out;\n};\n\n/**\n * React hook for reading and managing errors in ACUL (Advanced Customization of Universal Login).\n * With all validation and server-side errors. It groups errors into three kinds:\n * - `server` — errors returned by Auth0 or your own backend.\n * - `client` — errors from client-side validation (e.g., invalid form input).\n * - `developer` — errors caused by incorrect integration or SDK misuse.\n *\n * @supportedScreens\n * - The `useErrors` hook is available on every ACUL screen.\n *\n * @param options.includeDevErrors - When `true`, developer errors are included in\n * the returned list. Defaults to `false`.\n *\n * @returns An object of type {@link UseErrorsResult}, containing:\n * - `errors` — the full error list of type {@link ErrorsResult}, with helpers:\n * - `errors.byKind(kind, filter?)` — filter by error kind and optionally by field.\n * - `errors.byField(field, filter?)` — filter by field and optionally by kind.\n * - `hasError` — `true` if any error is currently present.\n * - `dismiss(id)` — remove a specific error by its ID.\n * - `dismissAll()` — clear all tracked errors.\n *\n * Typical usage is inside a form or screen component where you need to\n * reactively display errors and provide ways to dismiss them:\n *\n * @example\n * ```tsx\n * import { useErrors } from \"@auth0/auth0-acul-react\";\n *\n * export function SignupForm() {\n * const { errors, hasError, dismiss, dismissAll } = useErrors();\n *\n * return (\n * <div>\n * {hasError && (\n * <div className=\"mb-4\">\n * {errors.byKind(\"server\").map(err => (\n * <div key={err.id} className=\"text-red-600\">\n * {err.message}\n * <button onClick={() => dismiss(err.id)}>Dismiss</button>\n * </div>\n * ))}\n * </div>\n * )}\n *\n * <button onClick={dismissAll}>Clear All Errors</button>\n * </div>\n * );\n * }\n * ```\n *\n * In addition to rendering messages, you can filter by field or kind:\n * ```ts\n * console.log(errors.byKind('client')); // all client errors\n * console.log(errors.byKind('client', { field: 'username' })); // client errors for field 'username'\n * console.log(errors.byField('username')); // all errors for field 'username'\n * console.log(errors.byField('username', { kind: 'server' })); // server errors for field 'username'\n * ```\n */\n\nexport function useErrors(options: UseErrorOptions = {}): UseErrorsResult {\n const { includeDevErrors = false } = options;\n\n const snap = useSyncExternalStore(\n (cb) => errorStore.subscribe(cb),\n () => errorStore.snapshot()\n );\n\n const didInit = useRef(false);\n useEffect(() => {\n if (didInit.current) {\n return;\n }\n didInit.current = true;\n\n // Get server errors directly from TS SDK on first render.\n const server = (getServerErrors?.() ?? []) as Array<Omit<ErrorItem, 'id'>>;\n errorStore.replace('server', server);\n }, []);\n\n const serverTagged = useMemo(() => tag('server', snap.server), [snap.server]);\n const clientTagged = useMemo(() => tag('client', snap.client), [snap.client]);\n const devTagged = useMemo(() => tag('developer', snap.developer), [snap.developer]);\n\n const all = useMemo<ReadonlyArray<ErrorItem>>(\n () => Object.freeze([...(includeDevErrors ? devTagged : []), ...clientTagged, ...serverTagged]),\n [includeDevErrors, devTagged, clientTagged, serverTagged]\n );\n\n const errors: ErrorsResult = useMemo(() => {\n const arr = Object.assign([...all], {\n byKind(kind: ErrorKind, opts?: { field?: string }): ReadonlyArray<ErrorItem> {\n const base =\n kind === 'client' ? clientTagged : kind === 'developer' ? devTagged : serverTagged;\n return opts?.field ? Object.freeze(filterByField(base, opts.field)) : base;\n },\n byField(field: string, opts?: { kind?: ErrorKind }): ReadonlyArray<ErrorItem> {\n if (opts?.kind) {\n return arr.byKind(opts.kind, { field });\n }\n return Object.freeze(filterByField(all, field));\n },\n });\n return Object.freeze(arr);\n }, [all, clientTagged, devTagged, serverTagged]);\n\n const hasError = all.length > 0;\n\n const dismiss = useCallback((id: string) => {\n errorStore.remove(ERROR_KINDS, id);\n }, []);\n\n const dismissAll = useCallback(() => {\n errorStore.clear(ERROR_KINDS);\n }, []);\n\n return useMemo(\n () => ({ errors, hasError, dismiss, dismissAll }),\n [errors, hasError, dismiss, dismissAll]\n );\n}\n\n// ---------------- INTERNAL (SDK-only) ----------------\nconst isPromise = (v: unknown): v is Promise<unknown> =>\n typeof v === 'object' &&\n v !== null &&\n 'then' in v &&\n typeof (v as { then: unknown }).then === 'function';\n\nfunction withError<T>(actionOrPromise: (() => T | Promise<T>) | Promise<T>): T | Promise<T> {\n const handle = (e: unknown) => {\n const kind = classifyKind(e);\n const normalized = toErrorObject(e);\n switch (kind) {\n case 'client':\n errorManager.replaceClientErrors([normalized]);\n break;\n case 'developer':\n errorManager.replaceDeveloperErrors([normalized]);\n break;\n case 'server':\n errorManager.replaceServerErrors([normalized]);\n break;\n default: {\n console.error('[auth0-acul-react] Unhandled error:', e);\n throw e;\n }\n }\n };\n\n if (typeof actionOrPromise === 'function') {\n try {\n const result = (actionOrPromise as () => T | Promise<T>)();\n return isPromise(result)\n ? result.catch((e) => {\n handle(e);\n throw e;\n })\n : result;\n } catch (e) {\n handle(e);\n throw e;\n }\n }\n\n return actionOrPromise.catch((e) => {\n handle(e);\n throw e;\n });\n}\n\n/**\n * @hidden\n * Internal error manager for use by SDK methods.\n * Use the `useErrors` hook in React components instead.\n */\nexport const errorManager = {\n withError,\n\n replaceClientErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('client', list, opts.byField);\n } else {\n errorStore.replace('client', list);\n }\n },\n clearClientErrors() {\n errorStore.clear(['client']);\n },\n pushClientErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('client', list);\n },\n\n replaceDeveloperErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('developer', list, opts.byField);\n } else {\n errorStore.replace('developer', list);\n }\n },\n clearDeveloperErrors() {\n errorStore.clear(['developer']);\n },\n pushDeveloperErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('developer', list);\n },\n\n replaceServerErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('server', list, opts.byField);\n } else {\n errorStore.replace('server', list);\n }\n },\n clearServerErrors() {\n errorStore.clear(['server']);\n },\n pushServerErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('server', list);\n },\n\n syncServerErrors() {\n const server = (getServerErrors?.() ?? []) as Array<Omit<ErrorItem, 'id'>>;\n errorStore.replace('server', server);\n },\n};\n\nexport { ErrorItem, ErrorKind };\n"],"names":["filterByField","list","field","filter","e","cacheServer","WeakMap","cacheClient","cacheDev","tag","kind","arr","cache","hit","get","out","Object","freeze","map","set","useErrors","options","includeDevErrors","snap","useSyncExternalStore","cb","errorStore","subscribe","snapshot","didInit","useRef","useEffect","current","server","getServerErrors","replace","serverTagged","useMemo","clientTagged","client","devTagged","developer","all","errors","assign","byKind","opts","base","byField","hasError","length","dismiss","useCallback","id","remove","ERROR_KINDS","dismissAll","clear","errorManager","withError","actionOrPromise","handle","UserInputError","SDKUsageError","Auth0ServerError","classifyKind","normalized","code","Error","name","undefined","message","toErrorObject","replaceClientErrors","replaceDeveloperErrors","replaceServerErrors","console","error","result","v","then","catch","replacePartial","clearClientErrors","pushClientErrors","push","clearDeveloperErrors","pushDeveloperErrors","clearServerErrors","pushServerErrors","syncServerErrors"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../../../src/hooks/common/errors.ts"],"sourcesContent":["import {\n ConfigurationError,\n ValidationError,\n Auth0Error as Auth0ServerError,\n getErrors as getServerErrors,\n type Error as Auth0Error,\n} from '@auth0/auth0-acul-js';\nimport { useEffect, useMemo, useRef, useSyncExternalStore, useCallback } from 'react';\n\nimport { errorStore, ERROR_TYPES, type ErrorItem, type ErrorType } from '../../state/error-store';\n\nexport interface ErrorsResult extends ReadonlyArray<ErrorItem> {\n byType(type: ErrorType, opts?: { field?: string }): ReadonlyArray<ErrorItem>;\n byField(field: string, opts?: { type?: ErrorType }): ReadonlyArray<ErrorItem>;\n}\n\nexport interface UseErrorOptions {\n includeDevErrors?: boolean;\n}\n\nexport interface UseErrorsResult {\n errors: ErrorsResult;\n hasError: boolean;\n dismiss: (id: string) => void;\n dismissAll: () => void;\n}\n\nfunction classifyType(e: unknown): ErrorType | null {\n if (e instanceof ValidationError) {\n return 'validation';\n }\n if (e instanceof ConfigurationError) {\n return 'configuration';\n }\n if (e instanceof Auth0ServerError) {\n return 'auth0';\n }\n return null;\n}\n\nfunction toErrorObject(e: unknown): Omit<ErrorItem, 'id'> {\n return {\n code: (e as Auth0Error)?.code ?? (e instanceof Error ? e.name : undefined) ?? 'unknown_error',\n message: (e as Auth0Error)?.message ?? 'Unknown error',\n field: (e as Auth0Error)?.field,\n };\n}\n\nfunction filterByField<T extends { field?: string }>(\n list: ReadonlyArray<T>,\n field?: string\n): ReadonlyArray<T> {\n if (!field) {\n return list;\n }\n return list.filter((e) => e.field === field);\n}\n\n// caches for tagging\nconst cacheServer = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\nconst cacheValidation = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\nconst cacheDev = new WeakMap<ReadonlyArray<ErrorItem>, ReadonlyArray<ErrorItem>>();\n\nconst tag = (type: ErrorType, arr: ReadonlyArray<ErrorItem>): ReadonlyArray<ErrorItem> => {\n const cache = type === 'auth0' ? cacheServer : type === 'validation' ? cacheValidation : cacheDev;\n const hit = cache.get(arr);\n if (hit) {\n return hit;\n }\n const out = Object.freeze(arr.map((e) => Object.freeze({ ...e, type })));\n cache.set(arr, out);\n return out;\n};\n\n/**\n * React hook for reading and managing errors in ACUL (Advanced Customization of Universal Login).\n * With all validation and server-side errors. It groups errors into three types:\n * - `auth0` — errors returned by Auth0 or your own backend.\n * - `validation` — errors from client-side validation (e.g., invalid form input).\n * - `configuration` — errors caused by incorrect integration or SDK misuse.\n *\n * @supportedScreens\n * - The `useErrors` hook is available on every ACUL screen.\n *\n * @param options.includeDevErrors - When `true`, configuration errors are included in\n * the returned list. Defaults to `false`.\n *\n * @returns An object of type {@link UseErrorsResult}, containing:\n * - `errors` — the full error list of type {@link ErrorsResult}, with helpers:\n * - `errors.byType(type, filter?)` — filter by error type and optionally by field.\n * - `errors.byField(field, filter?)` — filter by field and optionally by type.\n * - `hasError` — `true` if any error is currently present.\n * - `dismiss(id)` — remove a specific error by its ID.\n * - `dismissAll()` — clear all tracked errors.\n *\n * Typical usage is inside a form or screen component where you need to\n * reactively display errors and provide ways to dismiss them:\n *\n * @example\n * ```tsx\n * import { useErrors } from \"@auth0/auth0-acul-react\";\n *\n * export function SignupForm() {\n * const { errors, hasError, dismiss, dismissAll } = useErrors();\n *\n * return (\n * <div>\n * {hasError && (\n * <div className=\"mb-4\">\n * {errors.byType(\"auth0\").map(err => (\n * <div key={err.id} className=\"text-red-600\">\n * {err.message}\n * <button onClick={() => dismiss(err.id)}>Dismiss</button>\n * </div>\n * ))}\n * </div>\n * )}\n *\n * <button onClick={dismissAll}>Clear All Errors</button>\n * </div>\n * );\n * }\n * ```\n *\n * In addition to rendering messages, you can filter by field or type:\n * ```ts\n * console.log(errors.byType('validation')); // all validation errors\n * console.log(errors.byType('validation', { field: 'username' })); // validation errors for field 'username'\n * console.log(errors.byField('username')); // all errors for field 'username'\n * console.log(errors.byField('username', { type: 'auth0' })); // auth0 errors for field 'username'\n * ```\n */\n\nexport function useErrors(options: UseErrorOptions = {}): UseErrorsResult {\n const { includeDevErrors = false } = options;\n\n const snap = useSyncExternalStore(\n (cb) => errorStore.subscribe(cb),\n () => errorStore.snapshot()\n );\n\n const didInit = useRef(false);\n useEffect(() => {\n if (didInit.current) {\n return;\n }\n didInit.current = true;\n\n // Get server errors directly from TS SDK on first render.\n const server = (getServerErrors?.() ?? []) as Array<Omit<ErrorItem, 'id'>>;\n errorStore.replace('auth0', server);\n }, []);\n\n const serverTagged = useMemo(() => tag('auth0', snap.auth0), [snap.auth0]);\n const clientTagged = useMemo(() => tag('validation', snap.validation), [snap.validation]);\n const devTagged = useMemo(() => tag('configuration', snap.configuration), [snap.configuration]);\n\n const all = useMemo<ReadonlyArray<ErrorItem>>(\n () => Object.freeze([...(includeDevErrors ? devTagged : []), ...clientTagged, ...serverTagged]),\n [includeDevErrors, devTagged, clientTagged, serverTagged]\n );\n\n const errors: ErrorsResult = useMemo(() => {\n const arr = Object.assign([...all], {\n byType(type: ErrorType, opts?: { field?: string }): ReadonlyArray<ErrorItem> {\n let base: ReadonlyArray<ErrorItem>;\n if (type === 'validation') {\n base = clientTagged;\n } else if (type === 'configuration') {\n base = devTagged;\n } else {\n base = serverTagged;\n }\n if (opts?.field) {\n return Object.freeze(filterByField(base, opts.field));\n }\n return base;\n },\n byField(field: string, opts?: { type?: ErrorType }): ReadonlyArray<ErrorItem> {\n if (opts?.type) {\n return arr.byType(opts.type, { field });\n }\n return Object.freeze(filterByField(all, field));\n },\n });\n return Object.freeze(arr);\n }, [all, clientTagged, devTagged, serverTagged]);\n\n const hasError = all.length > 0;\n\n const dismiss = useCallback((id: string) => {\n errorStore.remove(ERROR_TYPES, id);\n }, []);\n\n const dismissAll = useCallback(() => {\n errorStore.clear(ERROR_TYPES);\n }, []);\n\n return useMemo(\n () => ({ errors, hasError, dismiss, dismissAll }),\n [errors, hasError, dismiss, dismissAll]\n );\n}\n\n// ---------------- INTERNAL (SDK-only) ----------------\nconst isPromise = (v: unknown): v is Promise<unknown> =>\n typeof v === 'object' &&\n v !== null &&\n 'then' in v &&\n typeof (v as { then: unknown }).then === 'function';\n\nfunction withError<T>(actionOrPromise: (() => T | Promise<T>) | Promise<T>): T | Promise<T> {\n const handle = (e: unknown) => {\n const type = classifyType(e);\n const normalized = toErrorObject(e);\n switch (type) {\n case 'validation':\n errorManager.replaceValidationErrors([normalized]);\n break;\n case 'configuration':\n errorManager.replaceDeveloperErrors([normalized]);\n break;\n case 'auth0':\n errorManager.replaceServerErrors([normalized]);\n break;\n default: {\n console.error('[auth0-acul-react] Unhandled error:', e);\n throw e;\n }\n }\n };\n\n if (typeof actionOrPromise === 'function') {\n try {\n const result = (actionOrPromise as () => T | Promise<T>)();\n return isPromise(result)\n ? result.catch((e) => {\n handle(e);\n throw e;\n })\n : result;\n } catch (e) {\n handle(e);\n throw e;\n }\n }\n\n return actionOrPromise.catch((e) => {\n handle(e);\n throw e;\n });\n}\n\n/**\n * @hidden\n * Internal error manager for use by SDK methods.\n * Use the `useErrors` hook in React components instead.\n */\nexport const errorManager = {\n withError,\n\n replaceValidationErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('validation', list, opts.byField);\n } else {\n errorStore.replace('validation', list);\n }\n },\n clearValidationErrors() {\n errorStore.clear(['validation']);\n },\n pushValidationErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('validation', list);\n },\n\n replaceDeveloperErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('configuration', list, opts.byField);\n } else {\n errorStore.replace('configuration', list);\n }\n },\n clearDeveloperErrors() {\n errorStore.clear(['configuration']);\n },\n pushDeveloperErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('configuration', list);\n },\n\n replaceServerErrors(list: Array<Omit<ErrorItem, 'id'>>, opts?: { byField?: string }) {\n if (opts?.byField) {\n errorStore.replacePartial('auth0', list, opts.byField);\n } else {\n errorStore.replace('auth0', list);\n }\n },\n clearServerErrors() {\n errorStore.clear(['auth0']);\n },\n pushServerErrors(list: Omit<ErrorItem, 'id'> | Array<Omit<ErrorItem, 'id'>>) {\n errorStore.push('auth0', list);\n },\n\n syncServerErrors() {\n const server = (getServerErrors?.() ?? []) as Array<Omit<ErrorItem, 'id'>>;\n errorStore.replace('auth0', server);\n },\n};\n\nexport { ErrorItem, ErrorType };\n"],"names":["filterByField","list","field","filter","e","cacheServer","WeakMap","cacheValidation","cacheDev","tag","type","arr","cache","hit","get","out","Object","freeze","map","set","useErrors","options","includeDevErrors","snap","useSyncExternalStore","cb","errorStore","subscribe","snapshot","didInit","useRef","useEffect","current","server","getServerErrors","replace","serverTagged","useMemo","auth0","clientTagged","validation","devTagged","configuration","all","errors","assign","byType","opts","base","byField","hasError","length","dismiss","useCallback","id","remove","ERROR_TYPES","dismissAll","clear","errorManager","withError","actionOrPromise","handle","ValidationError","ConfigurationError","Auth0ServerError","classifyType","normalized","code","Error","name","undefined","message","toErrorObject","replaceValidationErrors","replaceDeveloperErrors","replaceServerErrors","console","error","result","v","then","catch","replacePartial","clearValidationErrors","pushValidationErrors","push","clearDeveloperErrors","pushDeveloperErrors","clearServerErrors","pushServerErrors","syncServerErrors"],"mappings":"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"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { useAuth0Themes } from './common/auth0-themes';
|
|
2
2
|
export { useCurrentScreen } from './common/current-screen';
|
|
3
|
-
export { errorManager, useErrors, type UseErrorOptions, type UseErrorsResult, type ErrorsResult, type
|
|
3
|
+
export { errorManager, useErrors, type UseErrorOptions, type UseErrorsResult, type ErrorsResult, type ErrorType, type ErrorItem, } from './common/errors';
|
|
4
4
|
export { ContextHooks } from './context';
|
|
5
5
|
export { useLoginIdentifiers } from './utility/login-identifiers';
|
|
6
6
|
export { useSignupIdentifiers } from './utility/signup-identifiers';
|
|
@@ -8,3 +8,4 @@ export { useMfaPolling, type MfaPollingResult, type ULError } from './utility/po
|
|
|
8
8
|
export { useResend, type UseResendReturn, type UseResendOptions } from './utility/resend-manager';
|
|
9
9
|
export { usePasswordValidation, type PasswordValidationResult, type PasswordComplexityRule, } from './utility/validate-password';
|
|
10
10
|
export { useUsernameValidation, type UsernameValidationResult, type UsernameValidationError, } from './utility/validate-username';
|
|
11
|
+
export { usePasskeyAutofill, type UsePasskeyAutofillResult } from './utility/passkey-autofill';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result object returned by {@link usePasskeyAutofill}.
|
|
3
|
+
*
|
|
4
|
+
* Provides a ref that can be attached to the username `<input>` element
|
|
5
|
+
* to automatically enable browser Conditional UI (passkey autofill).
|
|
6
|
+
*
|
|
7
|
+
* @see {@link usePasskeyAutofill}
|
|
8
|
+
* @category Passkeys
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export interface UsePasskeyAutofillResult {
|
|
12
|
+
/**
|
|
13
|
+
* A React ref that can be bound to the username `<input>` element.
|
|
14
|
+
*
|
|
15
|
+
* When attached, the SDK ensures the input’s `autocomplete`
|
|
16
|
+
* attribute is correctly set to `"username webauthn"`.
|
|
17
|
+
*
|
|
18
|
+
* If the developer already declared this attribute in markup,
|
|
19
|
+
* the ref is optional, the hook will still register Conditional
|
|
20
|
+
* Mediation correctly even without it.
|
|
21
|
+
*/
|
|
22
|
+
inputRef: React.RefObject<HTMLInputElement>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* React hook that enables browser **Conditional UI** (passkey autofill)
|
|
26
|
+
* for the login identifier field on the `login-id` screen.
|
|
27
|
+
*
|
|
28
|
+
* ---
|
|
29
|
+
* ### Behavior
|
|
30
|
+
* - The hook automatically initializes the browser’s Conditional Mediation
|
|
31
|
+
* API (`navigator.credentials.get({ mediation: "conditional" })`),
|
|
32
|
+
* allowing passkeys stored on the user’s device to appear directly in
|
|
33
|
+
* the username field’s autocomplete dropdown.
|
|
34
|
+
* - It **fails silently** on unsupported browsers and **never blocks** user input.
|
|
35
|
+
* - The registration is performed once per page lifecycle.
|
|
36
|
+
*
|
|
37
|
+
* ---
|
|
38
|
+
* ### Using the returned `ref`
|
|
39
|
+
* The returned `inputRef` is **optional**.
|
|
40
|
+
* - If you bind it to your `<input>` element, the SDK will ensure the element’s
|
|
41
|
+
* `autocomplete` attribute is correctly set to `"username webauthn"`.
|
|
42
|
+
* - If your input element **already has**
|
|
43
|
+
* `autocomplete="username webauthn"` declared in markup,
|
|
44
|
+
* you can skip binding the `ref` entirely, the hook will still register
|
|
45
|
+
* Conditional Mediation correctly. See {@link UsePasskeyAutofillResult}
|
|
46
|
+
*
|
|
47
|
+
* ---
|
|
48
|
+
* ### Example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* import { usePasskeyAutofill } from '@auth0/auth0-acul-react/login-id';
|
|
51
|
+
*
|
|
52
|
+
* export function LoginForm() {
|
|
53
|
+
* // Option 1: bind the ref for automatic attribute handling
|
|
54
|
+
* const { inputRef } = usePasskeyAutofill();
|
|
55
|
+
*
|
|
56
|
+
* return (
|
|
57
|
+
* <input
|
|
58
|
+
* ref={inputRef}
|
|
59
|
+
* id="username"
|
|
60
|
+
* placeholder="Username"
|
|
61
|
+
* autoComplete="username webauthn"
|
|
62
|
+
* />
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* // Option 2: works equally well without using the ref
|
|
67
|
+
* export function LoginFormWithoutRef() {
|
|
68
|
+
* usePasskeyAutofill(); // just call the hook once
|
|
69
|
+
*
|
|
70
|
+
* return (
|
|
71
|
+
* <input
|
|
72
|
+
* id="username"
|
|
73
|
+
* placeholder="Username"
|
|
74
|
+
* autoComplete="username webauthn"
|
|
75
|
+
* />
|
|
76
|
+
* );
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* ---
|
|
81
|
+
* @supportedScreens
|
|
82
|
+
* - `login-id`
|
|
83
|
+
*
|
|
84
|
+
* @category Passkeys
|
|
85
|
+
*/
|
|
86
|
+
export declare function usePasskeyAutofill(): UsePasskeyAutofillResult;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useRef as t,useLayoutEffect as e}from"react";import{getScreen as r}from"../../state/instance-store.js";const o="username webauthn";function n(){const n=r(),s=t(null),i=t(!1);return e(()=>{if(!i.current){i.current=!0;try{if(!n||"function"!=typeof n.registerPasskeyAutofill)return void console.warn("Passkey autofill unavailable: missing instance method");const t=s.current,e=t?.id;if(n.registerPasskeyAutofill(e),t){(t.getAttribute("autocomplete")??"").trim().toLowerCase()!==o&&t.setAttribute("autocomplete",o)}}catch(t){console.warn("usePasskeyAutofill failed:",t)}}},[n]),{inputRef:s}}export{n as usePasskeyAutofill};
|
|
2
|
+
//# sourceMappingURL=passkey-autofill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey-autofill.js","sources":["../../../src/hooks/utility/passkey-autofill.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\n\nimport { getScreen } from '../../state/instance-store';\n\nimport type { LoginIdMembers } from '@auth0/auth0-acul-js/login-id';\n\nconst REQUIRED_TOKENS = 'username webauthn';\n\n/**\n * Result object returned by {@link usePasskeyAutofill}.\n *\n * Provides a ref that can be attached to the username `<input>` element\n * to automatically enable browser Conditional UI (passkey autofill).\n *\n * @see {@link usePasskeyAutofill}\n * @category Passkeys\n * @public\n */\nexport interface UsePasskeyAutofillResult {\n /**\n * A React ref that can be bound to the username `<input>` element.\n *\n * When attached, the SDK ensures the input’s `autocomplete`\n * attribute is correctly set to `\"username webauthn\"`.\n *\n * If the developer already declared this attribute in markup,\n * the ref is optional, the hook will still register Conditional\n * Mediation correctly even without it.\n */\n inputRef: React.RefObject<HTMLInputElement>;\n}\n\n/**\n * React hook that enables browser **Conditional UI** (passkey autofill)\n * for the login identifier field on the `login-id` screen.\n *\n * ---\n * ### Behavior\n * - The hook automatically initializes the browser’s Conditional Mediation\n * API (`navigator.credentials.get({ mediation: \"conditional\" })`),\n * allowing passkeys stored on the user’s device to appear directly in\n * the username field’s autocomplete dropdown.\n * - It **fails silently** on unsupported browsers and **never blocks** user input.\n * - The registration is performed once per page lifecycle.\n *\n * ---\n * ### Using the returned `ref`\n * The returned `inputRef` is **optional**.\n * - If you bind it to your `<input>` element, the SDK will ensure the element’s\n * `autocomplete` attribute is correctly set to `\"username webauthn\"`.\n * - If your input element **already has**\n * `autocomplete=\"username webauthn\"` declared in markup,\n * you can skip binding the `ref` entirely, the hook will still register\n * Conditional Mediation correctly. See {@link UsePasskeyAutofillResult}\n *\n * ---\n * ### Example\n * ```tsx\n * import { usePasskeyAutofill } from '@auth0/auth0-acul-react/login-id';\n *\n * export function LoginForm() {\n * // Option 1: bind the ref for automatic attribute handling\n * const { inputRef } = usePasskeyAutofill();\n *\n * return (\n * <input\n * ref={inputRef}\n * id=\"username\"\n * placeholder=\"Username\"\n * autoComplete=\"username webauthn\"\n * />\n * );\n * }\n *\n * // Option 2: works equally well without using the ref\n * export function LoginFormWithoutRef() {\n * usePasskeyAutofill(); // just call the hook once\n *\n * return (\n * <input\n * id=\"username\"\n * placeholder=\"Username\"\n * autoComplete=\"username webauthn\"\n * />\n * );\n * }\n * ```\n *\n * ---\n * @supportedScreens\n * - `login-id`\n *\n * @category Passkeys\n */\nexport function usePasskeyAutofill(): UsePasskeyAutofillResult {\n const instance = getScreen<LoginIdMembers>();\n const inputRef = useRef<HTMLInputElement>(null);\n const initializedRef = useRef(false);\n\n useLayoutEffect(() => {\n if (initializedRef.current) return;\n initializedRef.current = true;\n\n try {\n if (!instance || typeof instance.registerPasskeyAutofill !== 'function') {\n console.warn('Passkey autofill unavailable: missing instance method');\n return;\n }\n\n const el = inputRef.current;\n const inputId = el?.id;\n\n // Fire-and-forget registration (fails silently)\n void instance.registerPasskeyAutofill(inputId);\n\n // Optionally correct the autocomplete attribute if the ref was used\n if (el) {\n const current = (el.getAttribute('autocomplete') ?? '').trim().toLowerCase();\n if (current !== REQUIRED_TOKENS) {\n el.setAttribute('autocomplete', REQUIRED_TOKENS);\n }\n }\n } catch (err) {\n console.warn('usePasskeyAutofill failed:', err);\n }\n }, [instance]);\n\n return { inputRef };\n}\n"],"names":["REQUIRED_TOKENS","usePasskeyAutofill","instance","getScreen","inputRef","useRef","initializedRef","useLayoutEffect","current","registerPasskeyAutofill","console","warn","el","inputId","id","getAttribute","trim","toLowerCase","setAttribute","err"],"mappings":"8GAMA,MAAMA,EAAkB,6BAwFRC,IACd,MAAMC,EAAWC,IACXC,EAAWC,EAAyB,MACpCC,EAAiBD,GAAO,GA8B9B,OA5BAE,EAAgB,KACd,IAAID,EAAeE,QAAnB,CACAF,EAAeE,SAAU,EAEzB,IACE,IAAKN,GAAwD,mBAArCA,EAASO,wBAE/B,YADAC,QAAQC,KAAK,yDAIf,MAAMC,EAAKR,EAASI,QACdK,EAAUD,GAAIE,GAMpB,GAHKZ,EAASO,wBAAwBI,GAGlCD,EAAI,EACWA,EAAGG,aAAa,iBAAmB,IAAIC,OAAOC,gBAC/CjB,GACdY,EAAGM,aAAa,eAAgBlB,EAEpC,CACF,CAAE,MAAOmB,GACPT,QAAQC,KAAK,6BAA8BQ,EAC7C,CAxB4B,GAyB3B,CAACjB,IAEG,CAAEE,WACX"}
|