@checkstack/auth-frontend 0.5.31 → 0.5.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/package.json +7 -6
- package/src/components/ResetPasswordPage.tsx +34 -6
- package/tsconfig.json +18 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @checkstack/auth-frontend
|
|
2
2
|
|
|
3
|
+
## 0.5.33
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [50e5f5f]
|
|
8
|
+
- @checkstack/auth-common@0.6.5
|
|
9
|
+
- @checkstack/common@0.8.0
|
|
10
|
+
- @checkstack/ui@1.7.1
|
|
11
|
+
- @checkstack/frontend-api@0.4.2
|
|
12
|
+
|
|
13
|
+
## 0.5.32
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 32d52c6: Fix and improve password reset flow + email branding:
|
|
18
|
+
|
|
19
|
+
- **Fix**: password reset emails were failing with "Malformed password reset URL: missing token parameter". Better-auth puts the reset token in the URL path (`/reset-password/{token}`), not as a `?token=` query param, so the previous URL-parsing logic always failed. Now uses the `token` argument better-auth passes to `sendResetPassword` directly.
|
|
20
|
+
- **UX**: the reset password page now validates the token on load via a new anonymous `validateResetToken` endpoint, so users see "Invalid Link" / "Link Expired" before typing a password rather than after submitting. Tokens are 24-char nanoid-style values (~143 bits of entropy), so exposing validity does not enable enumeration.
|
|
21
|
+
- **Fix**: transactional notifications were hardcoded to `importance: "critical"`, causing password reset emails to display a misleading "CRITICAL" badge. The `sendTransactional` contract now accepts an optional `importance` field that defaults to `"info"`.
|
|
22
|
+
- **Branding**: redesigned the email layout (`wrapInEmailLayout`) with a Checkstack-style engineering aesthetic — dark header with grid pattern, monospace importance badge, hardened CTA button (Outlook VML fallback + explicit text color), and force-light color scheme to prevent client auto-inversion from breaking text legibility.
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [32d52c6]
|
|
25
|
+
- Updated dependencies [32d52c6]
|
|
26
|
+
- Updated dependencies [32d52c6]
|
|
27
|
+
- @checkstack/frontend-api@0.4.1
|
|
28
|
+
- @checkstack/auth-common@0.6.4
|
|
29
|
+
- @checkstack/ui@1.7.0
|
|
30
|
+
|
|
3
31
|
## 0.5.31
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/auth-frontend",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.33",
|
|
4
|
+
"license": "Elastic-2.0",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "src/index.tsx",
|
|
6
7
|
"checkstack": {
|
|
@@ -11,27 +12,27 @@
|
|
|
11
12
|
"./api": "./src/api.ts"
|
|
12
13
|
},
|
|
13
14
|
"scripts": {
|
|
14
|
-
"typecheck": "
|
|
15
|
+
"typecheck": "tsgo -b",
|
|
15
16
|
"lint": "bun run lint:code",
|
|
16
17
|
"lint:code": "eslint . --max-warnings 0",
|
|
17
18
|
"test:e2e": "bunx playwright test"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
20
|
-
"@checkstack/frontend-api": "0.
|
|
21
|
+
"@checkstack/frontend-api": "0.4.1",
|
|
21
22
|
"@checkstack/common": "0.7.0",
|
|
22
|
-
"@checkstack/ui": "1.
|
|
23
|
+
"@checkstack/ui": "1.7.0",
|
|
23
24
|
"react": "^18.2.0",
|
|
24
25
|
"react-router-dom": "^6.22.0",
|
|
25
26
|
"lucide-react": "^0.344.0",
|
|
26
27
|
"better-auth": "^1.1.8",
|
|
27
|
-
"@checkstack/auth-common": "0.6.
|
|
28
|
+
"@checkstack/auth-common": "0.6.4"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"typescript": "^5.0.0",
|
|
31
32
|
"@types/react": "^18.2.0",
|
|
32
33
|
"@playwright/test": "^1.49.0",
|
|
33
34
|
"@checkstack/test-utils-frontend": "0.0.4",
|
|
34
|
-
"@checkstack/tsconfig": "0.0.
|
|
35
|
+
"@checkstack/tsconfig": "0.0.6",
|
|
35
36
|
"@checkstack/scripts": "0.1.2"
|
|
36
37
|
}
|
|
37
38
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
2
|
import { Link, useSearchParams, useNavigate } from "react-router-dom";
|
|
3
3
|
import { Lock, ArrowLeft, CheckCircle, AlertCircle } from "lucide-react";
|
|
4
|
-
import { authRoutes, passwordSchema } from "@checkstack/auth-common";
|
|
4
|
+
import { AuthApi, authRoutes, passwordSchema } from "@checkstack/auth-common";
|
|
5
5
|
import { resolveRoute, extractErrorMessage} from "@checkstack/common";
|
|
6
|
+
import { usePluginClient } from "@checkstack/frontend-api";
|
|
6
7
|
import {
|
|
7
8
|
Button,
|
|
8
9
|
Input,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
AlertContent,
|
|
19
20
|
AlertTitle,
|
|
20
21
|
AlertDescription,
|
|
22
|
+
LoadingSpinner,
|
|
21
23
|
} from "@checkstack/ui";
|
|
22
24
|
import { getAuthClientLazy } from "../lib/auth-client";
|
|
23
25
|
|
|
@@ -33,6 +35,16 @@ export const ResetPasswordPage = () => {
|
|
|
33
35
|
const [success, setSuccess] = useState(false);
|
|
34
36
|
const [validationErrors, setValidationErrors] = useState<string[]>([]);
|
|
35
37
|
const authClient = getAuthClientLazy();
|
|
38
|
+
const authApiClient = usePluginClient(AuthApi);
|
|
39
|
+
|
|
40
|
+
// Pre-validate token on load so users see invalid/expired errors before
|
|
41
|
+
// entering a password. Token entropy is high enough that exposing validity
|
|
42
|
+
// does not enable enumeration.
|
|
43
|
+
const { data: tokenValidation, isLoading: validatingToken } =
|
|
44
|
+
authApiClient.validateResetToken.useQuery(
|
|
45
|
+
{ token: token ?? "" },
|
|
46
|
+
{ enabled: Boolean(token) },
|
|
47
|
+
);
|
|
36
48
|
|
|
37
49
|
// Validate password on change
|
|
38
50
|
useEffect(() => {
|
|
@@ -90,8 +102,11 @@ export const ResetPasswordPage = () => {
|
|
|
90
102
|
}
|
|
91
103
|
};
|
|
92
104
|
|
|
93
|
-
// No token - show error
|
|
94
|
-
|
|
105
|
+
// No token, expired, or invalid - show error before user types a password.
|
|
106
|
+
const tokenInvalid =
|
|
107
|
+
!token || (tokenValidation && !tokenValidation.valid);
|
|
108
|
+
if (tokenInvalid) {
|
|
109
|
+
const isExpired = tokenValidation?.reason === "expired";
|
|
95
110
|
return (
|
|
96
111
|
<div className="min-h-[80vh] flex items-center justify-center">
|
|
97
112
|
<Card className="w-full max-w-md">
|
|
@@ -99,10 +114,13 @@ export const ResetPasswordPage = () => {
|
|
|
99
114
|
<div className="mx-auto w-12 h-12 rounded-full bg-destructive/10 flex items-center justify-center mb-2">
|
|
100
115
|
<AlertCircle className="h-6 w-6 text-destructive" />
|
|
101
116
|
</div>
|
|
102
|
-
<CardTitle className="text-2xl font-bold">
|
|
117
|
+
<CardTitle className="text-2xl font-bold">
|
|
118
|
+
{isExpired ? "Link Expired" : "Invalid Link"}
|
|
119
|
+
</CardTitle>
|
|
103
120
|
<CardDescription>
|
|
104
|
-
|
|
105
|
-
|
|
121
|
+
{isExpired
|
|
122
|
+
? "This password reset link has expired. Please request a new one."
|
|
123
|
+
: "This password reset link is invalid. Please request a new one."}
|
|
106
124
|
</CardDescription>
|
|
107
125
|
</CardHeader>
|
|
108
126
|
<CardFooter className="flex flex-col gap-4">
|
|
@@ -128,6 +146,16 @@ export const ResetPasswordPage = () => {
|
|
|
128
146
|
);
|
|
129
147
|
}
|
|
130
148
|
|
|
149
|
+
// While the token is being checked, show a spinner to avoid a flash of the
|
|
150
|
+
// password form before we know whether the link is valid.
|
|
151
|
+
if (validatingToken) {
|
|
152
|
+
return (
|
|
153
|
+
<div className="min-h-[80vh] flex items-center justify-center">
|
|
154
|
+
<LoadingSpinner />
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
131
159
|
// Success state
|
|
132
160
|
if (success) {
|
|
133
161
|
return (
|
package/tsconfig.json
CHANGED
|
@@ -2,5 +2,22 @@
|
|
|
2
2
|
"extends": "@checkstack/tsconfig/frontend.json",
|
|
3
3
|
"include": [
|
|
4
4
|
"src"
|
|
5
|
+
],
|
|
6
|
+
"references": [
|
|
7
|
+
{
|
|
8
|
+
"path": "../auth-common"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"path": "../common"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"path": "../frontend-api"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "../test-utils-frontend"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "../ui"
|
|
21
|
+
}
|
|
5
22
|
]
|
|
6
|
-
}
|
|
23
|
+
}
|