@passflow/react 0.16.0 → 0.18.0

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.
Files changed (82) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +42 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.es.js +146 -133
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/src/components/flow/passflow/index.d.ts.map +1 -1
  8. package/dist/src/components/form/reset-password/index.d.cts +2 -0
  9. package/dist/src/components/form/reset-password/index.d.ts +2 -0
  10. package/dist/src/components/form/reset-password/index.d.ts.map +1 -1
  11. package/dist/src/components/form/signin/index.d.ts.map +1 -1
  12. package/dist/src/components/form/signup/index.d.ts.map +1 -1
  13. package/dist/src/components/provider/passflow-provider.d.cts +1 -0
  14. package/dist/src/components/provider/passflow-provider.d.ts +1 -0
  15. package/dist/src/components/provider/passflow-provider.d.ts.map +1 -1
  16. package/dist/src/components/provider/use-dispose-on-replace.d.cts +17 -0
  17. package/dist/src/components/provider/use-dispose-on-replace.d.ts +17 -0
  18. package/dist/src/components/provider/use-dispose-on-replace.d.ts.map +1 -0
  19. package/dist/src/components/ui/button/index.d.ts.map +1 -1
  20. package/dist/src/components/ui/fields/field-otp.d.cts +3 -1
  21. package/dist/src/components/ui/fields/field-otp.d.ts +3 -1
  22. package/dist/src/components/ui/fields/field-otp.d.ts.map +1 -1
  23. package/dist/src/components/ui/login-screen/email-code.d.cts +10 -0
  24. package/dist/src/components/ui/login-screen/email-code.d.ts +10 -0
  25. package/dist/src/components/ui/login-screen/email-code.d.ts.map +1 -0
  26. package/dist/src/components/ui/login-screen/index.d.cts +1 -1
  27. package/dist/src/components/ui/login-screen/index.d.ts +1 -1
  28. package/dist/src/components/ui/login-screen/index.d.ts.map +1 -1
  29. package/dist/src/components/ui/login-screen/login-screen.d.ts.map +1 -1
  30. package/dist/src/components/ui/login-screen/new-password.d.cts +10 -0
  31. package/dist/src/components/ui/login-screen/new-password.d.ts +10 -0
  32. package/dist/src/components/ui/login-screen/new-password.d.ts.map +1 -0
  33. package/dist/src/components/ui/login-screen/status.d.ts.map +1 -1
  34. package/dist/src/components/ui/login-screen/types.d.cts +62 -3
  35. package/dist/src/components/ui/login-screen/types.d.ts +62 -3
  36. package/dist/src/components/ui/login-screen/types.d.ts.map +1 -1
  37. package/dist/src/context/auth-context.d.cts +5 -4
  38. package/dist/src/context/auth-context.d.ts +5 -4
  39. package/dist/src/context/auth-context.d.ts.map +1 -1
  40. package/dist/src/hooks/index.d.cts +3 -1
  41. package/dist/src/hooks/index.d.ts +3 -1
  42. package/dist/src/hooks/index.d.ts.map +1 -1
  43. package/dist/src/hooks/use-email-code-step.d.cts +39 -0
  44. package/dist/src/hooks/use-email-code-step.d.ts +39 -0
  45. package/dist/src/hooks/use-email-code-step.d.ts.map +1 -0
  46. package/dist/src/hooks/use-join-invite.d.ts.map +1 -1
  47. package/dist/src/hooks/use-refresh-status.d.cts +36 -0
  48. package/dist/src/hooks/use-refresh-status.d.ts +36 -0
  49. package/dist/src/hooks/use-refresh-status.d.ts.map +1 -0
  50. package/dist/src/hooks/use-reset-password.d.cts +14 -1
  51. package/dist/src/hooks/use-reset-password.d.ts +14 -1
  52. package/dist/src/hooks/use-reset-password.d.ts.map +1 -1
  53. package/dist/src/hooks/use-session-expired.d.cts +8 -4
  54. package/dist/src/hooks/use-session-expired.d.ts +8 -4
  55. package/dist/src/hooks/use-session-expired.d.ts.map +1 -1
  56. package/dist/src/hooks/use-signin.d.cts +6 -0
  57. package/dist/src/hooks/use-signin.d.ts +6 -0
  58. package/dist/src/hooks/use-signin.d.ts.map +1 -1
  59. package/dist/src/hooks/use-signup.d.cts +6 -0
  60. package/dist/src/hooks/use-signup.d.ts +6 -0
  61. package/dist/src/hooks/use-signup.d.ts.map +1 -1
  62. package/dist/src/index.d.cts +1 -0
  63. package/dist/src/index.d.ts +1 -0
  64. package/dist/src/index.d.ts.map +1 -1
  65. package/dist/src/types/email-verification.d.cts +18 -0
  66. package/dist/src/types/email-verification.d.ts +18 -0
  67. package/dist/src/types/email-verification.d.ts.map +1 -0
  68. package/dist/src/types/index.d.cts +1 -0
  69. package/dist/src/types/index.d.ts +1 -0
  70. package/dist/src/types/index.d.ts.map +1 -1
  71. package/dist/src/utils/auth-error.d.cts +46 -0
  72. package/dist/src/utils/auth-error.d.ts +46 -0
  73. package/dist/src/utils/auth-error.d.ts.map +1 -1
  74. package/dist/src/utils/email-verification.d.cts +44 -0
  75. package/dist/src/utils/email-verification.d.ts +44 -0
  76. package/dist/src/utils/email-verification.d.ts.map +1 -0
  77. package/dist/src/utils/get-url-errors.d.ts.map +1 -1
  78. package/dist/src/utils/index.d.cts +2 -1
  79. package/dist/src/utils/index.d.ts +2 -1
  80. package/dist/src/utils/index.d.ts.map +1 -1
  81. package/dist/style.css +1 -1
  82. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,42 @@
2
2
 
3
3
  All notable changes to `@passflow/react` are documented in this file.
4
4
 
5
+ ## [0.18.0] - 2026-11-03
6
+
7
+ ### Added
8
+
9
+ - Email verification code step. When an app's registration policy requires a verified email, `/auth/register` and `/auth/login` may answer with a challenge instead of tokens. Sign-up and sign-in then show a code screen bound to that challenge. The submitted code goes to `/auth/validate`, and its answer continues the flow as before: second factor, PKCE or redirect. Resend repeats the original request. Cancel goes back to the form.
10
+ - When the server's code budget is spent and it emails a link instead, the flow shows a "check your email" screen with no code input. The link opens the reset-password screen with a continuation grant. That screen titles itself "Create your password" and signs the user in with the tokens `/auth/password/change` returns.
11
+ - `useEmailCodeStep()` (with `UseEmailCodeStep` and `UseEmailCodeStepOptions` types) drives the code step for custom UIs. Also exported: `EmailCodeStep`, `EmailVerificationStep`, `readEmailVerificationStep`, `emailCodeStepReducer`, `initialEmailCodeStepState`, and the error helpers `authErrorFrom`, `authRedirectErrorFrom`, `invitationJoinErrorFrom`, `emailCodeErrorMessage`, `newPasswordErrorMessage`, `serverMessageFor` and `isPasswordSavedRateLimit`.
12
+ - `LoginScreen` states `email-code` and `new-password`, and an `info` tone for the `status` state, each with a Storybook story.
13
+ - `Button` honours `aria-disabled`: it looks disabled and ignores clicks but stays focusable, so focus is not lost while a resend cooldown runs.
14
+
15
+ ### Changed
16
+
17
+ - Requires `@passflow/core` `^0.22.0`, which adds `verifyEmailCode` and the `EmailVerificationRequired` event.
18
+ - For these error ids the forms show the server's localized `error.message` instead of fixed copy: `error.registration.email.domain_not_allowed`, `email.required`, `email.not_verified_by_provider`, `error.invite.email.domain_not_allowed`, `error.verification.code.rate_limited`, and wrong, expired or used codes. The same list applies to errors that arrive in the URL from a federated sign-in. Other ids keep the fixed copy.
19
+ - The reset-password screen is built on `LoginScreen`. Its outer wrapper class is unchanged, but the elements inside it are different, so `custom_css` rules aimed at its inner classes need updating.
20
+
21
+ ### Fixed
22
+
23
+ - A 429 from the server is recognised whether core passes it on as a `PassflowError` or as a raw HTTP error, so rate limits show the rate-limit message instead of a generic failure.
24
+ - A URL error message containing a literal `%` no longer breaks decoding.
25
+
26
+ ## [0.17.0] - 2026-11-03
27
+
28
+ ### Changed
29
+
30
+ - Requires `@passflow/core` `^0.21.0`: one token refresh per browser across tabs, with transient failures kept apart from the end of a session. See core's `docs/token-refresh.md`, "Migrating from 0.20.1". What reaches React apps: a network error or 5xx during refresh no longer signs the user out; `SessionExpired` fires only at a real end; `SignOut` fires once per sign-out.
31
+ - `SessionExpiredReason` is core's type, re-exported from the package root as before. It adds `'successor_timeout'` and `'identity_changed'`, so `useSessionExpired` and `AuthProvider`'s `onSessionExpired` can receive them. An exhaustive `switch` over the reason needs the new cases.
32
+
33
+ ### Added
34
+
35
+ - `useRefreshStatus()` returns `{ isFailing, since, nextRetryAt }` while token refresh is failing transiently (`RefreshFailing` until `RefreshRecovered`), for a "reconnecting" notice. Call it in a component that lives as long as the app: a component that mounts mid-episode starts idle.
36
+
37
+ ### Fixed
38
+
39
+ - `PassflowProvider` disposes the `Passflow` instances it replaces (its state changes on app ID discovery and app settings) and the one it holds on unmount. From core 0.21 each instance holds refresh timers, a `BroadcastChannel` and Web Locks, so an undisposed one went on acting as another tab.
40
+
5
41
  ## [0.16.0] - 2026-11-03
6
42
 
7
43
  ### Breaking
package/README.md CHANGED
@@ -46,6 +46,8 @@ This is a SDK for react application.
46
46
  - [useJoinInvite](#usejoininvite)
47
47
  - [useLogout](#uselogout)
48
48
  - [usePasswordlessComplete](#usepasswordlesscomplete)
49
+ - [useSessionExpired](#usesessionexpired)
50
+ - [useRefreshStatus](#userefreshstatus)
49
51
 
50
52
  to install just type:
51
53
 
@@ -947,3 +949,43 @@ const { fetch, isLoading, isError, error } = usePasswordlessComplete();
947
949
  | isLoading | `boolean` | Loading state |
948
950
  | isError | `boolean` | Error state |
949
951
  | error | `string` | Error message |
952
+
953
+ ### useSessionExpired
954
+ Hook for reacting to the end of a session, for example to redirect to your login page.
955
+
956
+ ```typescript
957
+ const { isSessionExpired, expiredReason, resetSessionExpired } = useSessionExpired({
958
+ onSessionExpired: (reason) => navigate('/signin'),
959
+ });
960
+ ```
961
+
962
+ `SessionExpired` fires only when the session has really ended: the last auth strike (`'refresh_failed'`), no successor token pair in time (`'successor_timeout'`), or another user's tokens in storage (`'identity_changed'`). A transient refresh failure (network error, 5xx) keeps the session and shows up as `RefreshFailing` / `RefreshRecovered` instead; use [useRefreshStatus](#userefreshstatus) for that. The state resets on `SignIn` and `Register`.
963
+
964
+ | Parameter | Type | Description |
965
+ |-----------|------|-------------|
966
+ | onSessionExpired | `(reason: SessionExpiredReason) => void` (optional) | Called when the session ends |
967
+
968
+ **Returns:**
969
+
970
+ | Property | Type | Description |
971
+ |----------|------|-------------|
972
+ | isSessionExpired | `boolean` | True once the session has ended |
973
+ | expiredReason | `SessionExpiredReason \| null` | Why it ended (`SessionExpiredReason` is exported from `@passflow/core`) |
974
+ | resetSessionExpired | `() => void` | Clears the expired state |
975
+
976
+ ### useRefreshStatus
977
+ Hook for showing a "connection trouble" notice while token refresh is failing transiently. The session is kept during the episode; show the notice on `RefreshFailing` and hide it on `RefreshRecovered`.
978
+
979
+ ```typescript
980
+ const { isFailing, since, nextRetryAt } = useRefreshStatus();
981
+ ```
982
+
983
+ Set by `RefreshFailing`. Cleared by `RefreshRecovered`, `SessionExpired`, `SignOut`, `SignIn` and `Register`. The episode is known only from events, so a component that mounts after `RefreshFailing` starts idle: call the hook in a component that lives as long as the app, near `PassflowProvider`.
984
+
985
+ **Returns:**
986
+
987
+ | Property | Type | Description |
988
+ |----------|------|-------------|
989
+ | isFailing | `boolean` | True inside a transient-failure episode |
990
+ | since | `number \| null` | Epoch ms of the episode's first failure |
991
+ | nextRetryAt | `number \| null` | Epoch ms of the pending retry, when known |